user1475692
user1475692

Reputation: 95

Check if element exists in collection in multithreaded application

Let's assume that we have two threads and a collection:

ConcurrentDictionary<int, object[]> lists = new ConcurrentDictionary<int, object[]>();

1) One thread processes elements in collection and then remove elements from collection

foreach(object[] elem in lists.Values)
{
    //do somethind
    lists.TryRemove(key, out vals);
}

2) Second thread add elements to collection and then it need to be able to check elements status:

lists.Add(10, some_object);

...

if(lists.ContainsKey(10))
{

    //How can I be sure that at this moment element is still exists ?
    //Thread may be preempted after if() {} and second thread 
    //can remove object from collection
}

Upvotes: 5

Views: 525

Answers (2)

McGarnagle
McGarnagle

Reputation: 102793

You are meant to use TryGetValue, as this makes sure the check/get is atomic:

object[] val;
if(lists.TryGetValue(10, out val)) {
    // Here you have a reference to the object[], even if it has subsequently been removed
}

Of course, the thread-safety of the object[] itself is another question, which can't be solved by ConcurrentDictionary. (For example, if say both threads modify the objects somehow, and the objects are not thread-safe, then you would need to use a lock inside the TryGetValue block.)

Upvotes: 7

Mike Dinescu
Mike Dinescu

Reputation: 55760

In that case you will need to write your own locking around the code that accesses the dictionary. And at that point a concurrent dictionary is not necessarily needed anymore because you would be synchronizing access to it outside the dictionary so essentially duplicating the efforts.

// in thread 1
lock(COMMON_LOCK_OBJECT)
{
   foreach(object[] elem in lists.Values)
   {
     //do somethind
     lists.TryRemove(key, out vals);
   }

}

An in thread 2:

lock(COMMON_LOCK_OBJECT)
{
    lists.Add(10, some_object);

    ...

    if(lists.ContainsKey(10))
    {

    }
}

Upvotes: 0

Related Questions