11
string Get(string key){
   lock(_sync){
    //   DoSomething
   }
}

If DoSomething depend only on key, I want key dependent lock. I think it may be dictionary with sync objects. Is there any complete solution?

Something like real example What is the best way to lock cache in asp.net?

Community
  • 1
  • 1
dotneter
  • 1,689
  • 2
  • 15
  • 24
  • Use a concurrent structure like a ConcurrentDictionary or better yet an actual cache. I can suggest a cache if you want (mention my name with a @ before in the comment). – Danny Varod Jan 18 '18 at 16:49

1 Answers1

22

Well, you could create a Dictionary<string, object> and lazily populate it with objects to lock on. For example:

readonly Dictionary<string, object> dictionary = new Dictionary<string, object>();
readonly object dictionaryLock = new object();

string Get(string key) {
    object bodyLock;
    lock (dictionaryLock) {
        if (!dictionary.TryGetValue(key, out bodyLock)) {
            bodyLock = new object();
            dictionary[key] = bodyLock;
        }
    }
    lock (bodyLock) {
        ...
    }
}

If you need to lock in the same way elsewhere, I'd move the "lock finding" part to a helper method. Note that if you're using .NET 4, ConcurrentDictionary can make this easier, and without the use of an extra lock.

Note that there's nothing which will ever clear the dictionary in this design... do you have a fixed set of keys (in which case that's okay) or could it grow forever?

One thing which you appear to already have realised: locking on the key itself would be a really bad idea. Equal keys could be distinct objects, and if there's any other code which locks on strings as well, it could interfere with this code. Locking on strings is almost always wrong :)

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Shouldn't the variable `locks` declared on line 1 be `dictionary` for the rest of the code block to make sense? – maxp Feb 21 '13 at 11:25
  • @JonSkeet Is the solution with `ConcurrentDictionary` to invoke `GetOrAdd` with a value factory to generate a new lock object should the key not exist? – Pero P. May 13 '13 at 19:00
  • 1
    @scriptfromscratch: Yes, that's probably what I meant :) – Jon Skeet May 13 '13 at 19:04
  • @JonSkeet What if the there are millions of keys ? Don't you think that we should remove the key from dictionary after processing is complete ? – Jay Shah Jan 10 '18 at 20:27
  • 1
    @Jay: Potentially - it depends if you're going to be using those keys many times over. Having a large constant memory usage may well be better than constantly mutating the dictionary. – Jon Skeet Jan 10 '18 at 20:34
  • @JonSkeet Correct. Also Is there any problem if I lock directly on dictionary object instead of using separate dictionaryLock object ? I have added my answer below, Please feel free to provide your suggestions if you find any issues with that. – Jay Shah Jan 10 '18 at 20:53
  • @Jay: You can, but it becomes tricky if the dictionary is exposed to any other code that might lock on it. (I don't have time to comment on your answer right now.) – Jon Skeet Jan 10 '18 at 21:19
  • Could you please add the solution with the `ConcurrentDictionary`? I was so stupid I just replaced the `Dictionary` with the `ConcurrentDictionary` and removed the `dictionaryLock`. The result was... extremely wrong. So I would like to warn others before they do the same mistake. – vojta Jan 17 '18 at 13:13
  • @vojta: You should be able to get it to work without `dictionaryLock`, but with `GetOrAdd` or similar. (I'd have to check the API - it's late and I have awful network.) – Jon Skeet Jan 17 '18 at 22:02
  • 1
    @vojta [Here](https://stackoverflow.com/a/19009026/1159478) is a solution to the problem using a concurrent dictionary. – Servy Jan 18 '18 at 19:26