3

I'm using a dictionary to collect events in a multithread application, using lock when I add an event and not using it when I search for one. Every hour or so I run a cleanup of the events older than a certain time. Very simple and it works.

I'd like to move to a ConcurrentDictionary to remove the locks, and I thought I just had to add "Concurrent" and change the Add to TryAdd. But then I incurred in the error that LINQ returns only ToDictionary. I can obviusly not use LINQ, but I was curios to know if there's something I can do to preserve it. And more important, is there something I else I should consider before moving to ConcurrentDictionry?

public class messageResult { public Result result; public DateTime receivedTime; } public Dictionary<Guid, messageResult> events = new Dictionary<Guid, messageResult>(); lock (events) { events = events.Where(p => p.Value.receivedTime >= t).ToDictionary(p => p.Key, p => p.Value); } 

Thanks

6
  • 1
    Why don't you use System.Runtime.Caching.MemoryCache? Commented Oct 1, 2013 at 20:56
  • 1
    "using lock when I add an event and not using it when I search for one" Locks don't work that way, you must lock when reading to prevent a write happening while you read. However you can do what you want to do (allow multiple readers and a single writer) by useing ReaderWriterLockSlim instead, this will let you have many readers who all stop when the one writer wants to write. Commented Oct 1, 2013 at 21:25
  • @L.B thanks for the suggestion, but what are the advantages over my shared Dictionary instance? Commented Oct 4, 2013 at 9:58
  • @ScottChamberlain I'm certain that no thread is going to read the value I'm writing for at least a few seconds, that's why I thought that locking only when writing was sufficient. Am I wrong? Should I really lock every time I access the object? I'll check anyway your suggestion for ReaderWriterLockSlim Commented Oct 4, 2013 at 10:03
  • @MattiaDurli It's not that you need to lock on the same key, you need to lock on the same bucket. If you try to read and write to the same bucket inside the dictionary it can cause problems. Commented Oct 4, 2013 at 13:37

2 Answers 2

0

It looks like the ToDictionary extension method is not so complicated and you can create your own version.

But note that ToDictionary returns new object while you would like to have one dictionary and share it between your threads.

You should not lock on mutable variable (and you are also changing the actual reference to events), create private readonly variable and use it for locking.

Sign up to request clarification or add additional context in comments.

2 Comments

Can you elaborate "create private readonly variable and use it for locking"? I don't understand how can I use a readonly variable in this context
0

ToDictionary returns a new instance... which is different than your shared instance.

You want to modify your shared instance and should write code which does that:

foreach(var kvp in events.Where(...).ToList()) { var val = kvp.Value; events.TryRemove(kvp.Key out val); } 

2 Comments

Yes you're right, it returns a new instance, but since it's in a lock it should work (actually it works). Is it wrong what I'm doing or just unperformant?
By the way, your suggestion is to use a ConcurrentDictionay, but then why to iterate the elements you convert it to a List, can't I iterate directly through the ConcurrentDictionary elements and TryRemove the expired ones?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.