tags:

views:

922

answers:

5

Hello, I need to implement concurrent Dictionary because .Net does not contain concurrent implementation for collections(Since .NET4 will be contains). Can I use for it "Power Threading Library" from Jeffrey Richter or present implemented variants or any advice for implemented? Thanks ...

+3  A: 

You can use Reflector to view the source code of the concurrent implementation of .NET 4.0 RC and copy it to your own code. This way you will have the least problems when migrating to .NET 4.0.

Steven
Unless it uses any new features that are not available in dotNET 3.5. And there could be copyright issues here.
Henk Holterman
Thank you, I thought about it.
jitm
I would discourage you to reverse-engineering the 4.0 Fx.. This is a solvable/solved problem for which there are known/tested solutions. You can use the 4.0 Fx for inspiration, but otherwise I don't think this is sound advice.
Ryan Emerle
A: 

This is a small example of what you could do to protect your methods. You would have to protect any methods that edit or read from the internal data structure to make sure you don't have two threads doing mutually exclusive things.

There might be an easier way, but this is how I would do it.

class ConcurrentDictionary<TKey, TValue> : Dictionary<TKey, TValue>
{
    public ConcurrentDictionary():base(){}
    public ConcurrentDictionary(int capacity) : base(capacity) { }

    static AutoResetEvent addEvent = new AutoResetEvent(true);
    public  void Add (TKey key,TValue value)
    {
        addEvent.WaitOne();
        base.Add(key,value);
        addEvent.Set();
    }
}
madmik3
I don't think this is the best approach, particularly because the methods for `Dictionary<TKey, TValue>` are not virtual (you'd have to add `new` to your `Add` definition); so if the user simply accesses this object as a `Dictionary<TKey, TValue>`, suddenly it won't be synchronized. Also, why would you make `addEvent` static? Also, just synchronizing `Add` isn't going to make the collection thread-safe; you need to synchronize *any* method that modifies the collection. (So, I'd call it something like `modifyEvent` instead of `addEvent`.)
Dan Tao
Not to mention using an EventWaitHandle is unnecessary and confusing since you're not really signalling - you're controlling access to a resource. A Monitor would be more appropriate.
Ryan Emerle
yeah, the AutoResetEvent does not have to be static. But I don't understand the function need to me marked as virtual. This function will get called when you call myDict.add(...). You should be able to control the collection this way. (Or at least I think so)
madmik3
@madmik: Your `ConcurrentDictionary` class derives from `Dictionary`, which means I could write `Dictionary<int, int> d = new ConcurrentDictionary<int, int>();`. Then if I called `d.Add` it would use `Dictionary.Add` instead of `ConcurrentDictionary.Add`. Not good! Also, your `AutoResetEvent` doesn't just "not have to be" static; it really *should not be*. Otherwise you're synchronizing all calls to `Add` on *any* instance of this class. That doesn't make much sense, does it?
Dan Tao
@madmik3 : You need to make the declare the Add function as public void new Add(TKey key, TValue value) so that it properly hides the inherrited Dictionary Add method.
galford13x
+2  A: 

I wrote a concurrent dictionary myself (prior to .NET 4.0's System.Collections.Concurrent namespace); there's not much to it. You basically just want to make sure certain methods are not getting called at the same time, e.g., Contains and Remove or something like that.

What I did was to use a ReaderWriterLock (in .NET 3.5 and above, you could go with ReaderWriterLockSlim) and call AcquireReaderLock for all "read" operations (like this[TKey], ContainsKey, etc.) and AcquireWriterLock for all "write" operations (like this[TKey] = value, Add, Remove, etc.). Be sure to wrap any calls of this sort in a try/finally block, releasing the lock in the finally.

It's also a good idea to modify the behavior of GetEnumerator slightly: rather than enumerate over the existing collection, make a copy of it and allow enumeration over that. Otherwise you'll face potential deadlocks.

Dan Tao
+3  A: 

I wrote a thread-safe wrapper for the normal Dictionary class that uses Interlocked to protect the internal dictionary. Interlocked is by far the fastest locking mechanism available and will give much better performance than ReaderWriterLockSlim, Monitor or any of the other available locks.

The code was used to implement a Cache class for Fasterflect, which is a library to speed up reflection. As such we tried a number of different approaches in order to find the fastest possible solution. Interestingly, the new concurrent collections in .NET 4 are noticeably faster than my implementation, although both are pretty darn fast compared to solutions using a less performance locking mechanism. The implementation for .NET 3.5 is located inside a conditional region in the bottom half of the file.

Morten Mertner
I took a look at your Fasterflect home page and saw your Person class example having that instance count inside the class. Wouldn't that open you to concurrency issues as there is no locking on it? I recently did some verification that C# ++/-- operators are not atomic and I didn't see any information that contradicted my understanding.
Chris Marisic
The Person class is just a sample class used to show how Fasterflect can be used. It is not meant to be thread safe. The code I was referring to above is the Cache class located in the main Fasterflect project. Click the Cache link above to go directly to the source browser on CodePlex.
Morten Mertner
A: 

Here's a simple implementation that uses sane locking (though Interlocked would likely be faster): http://www.tech.windowsapplication1.com/content/the-synchronized-dictionarytkey-tvalue

Essentially, just create a Dictionary wrapper/decorator and synchronize access to any read/write actions.

When you switch to .Net 4.0, just replace all of your overloads with delegated calls to the underlying ConcurrentDictionary.

Ryan Emerle