-1

I have a WCF service in IIS App pool. Method of WCF service receives some data in JSON, like {"object": "someobject", "payload": [int key]}.
For each request I running new thread to work with key.
Key is adding to ConcurrentDictionary and locks value of ConcurrentDictionary.
Purpose of this is: only one examplar of key can run one time, example:
Thread 1-Running with key 1
Thread 2-Running with key 2
Thread 3-Waiting lock in Thread 1
But when I remove key from ConcurrentDictionary, another thread already get the value by key and works with it. How to avoid this? Example of thread handler near

static ConcurrentDictionary<string, object> taskDictionary=new ConcurrentDictionary<string, object>();
static void ThreadHandler(int key)
        {   
            try
            {
                var  lockElem=taskDictionary.GetOrAdd(key, new object());
//Thread 3 get value by key 1 here and waits here
                lock(lockElem)
                {
                    taskDictionary.TryRemove(key, out _);
// but Thread 1 removes value by key 1 here
//and Thread 4 can add value in Dictionary with same key (key 1)
                }
            }
            finally
            {
            }
        }

Problem is in this case: Thread 1 uses GetOrAdd, then lock value, then TryRemove. In this time Thread 3. uses GetOrAdd, taking value, but waiting lock from Thread 1. When lock from Thread 1 releases, Thread 3 lock removed value. In this time Thread 4 uses GetOrAdd, and creating new dictionary element (which not match with value taken by Thread 3). And we have 2 threads (Thread 3 and Thread 4) which working with same key.

1 Answers1

0

The TryRemove function already gives you back a default object if it does not exist in the dictionary yet, so you could simply do:

static ConcurrentDictionary<int, object> taskDictionary=new ConcurrentDictionary<int, object>();
static void ThreadHandler(int key)
{   
    try
    {
        object obj;

        // Remove object with key = 'key', or create a new object if it does not yet exist
        taskDictionary.TryRemove(key, out obj);

        // Do whatever you need to do with 'obj'

        // Add the object (back) to the dictionary if necessary
        taskDictionary.GetOrAdd(key, obj);
    }
    finally
    {
    }
}
Bart van der Drift
  • 1,287
  • 12
  • 30
  • how it help me in lock element by key? – Александр Бахматов May 01 '19 at 07:24
  • You remove the key from the Dictionary, so there is no longer any need to lock the element, since no other thread will be able to fetch it from the DIctionary. – Bart van der Drift May 01 '19 at 07:31
  • but first thread, what want access to object, cant get object by TryRemove, right? – Александр Бахматов May 01 '19 at 07:45
  • Yes, TryRemove will return the object that has been removed from the Dictionary. Because the method is atomic, only one thread will be able to access the element before it is removed. Please see here for more information: https://learn.microsoft.com/en-us/dotnet/api/system.collections.concurrent.concurrentdictionary-2.tryremove?view=netframework-4.8 – Bart van der Drift May 01 '19 at 08:10
  • How help the first thread to add a element to dictionary? I need than another threads waiting until lock is released, coz it's like queue of requests to dictionary, the next thread with same key need to wait, while previous worker do work. – Александр Бахматов May 01 '19 at 08:37
  • In that case I do not fully understand the problem with your initial code, because there the second thread will wait under the first thread is finished with the element. Maybe you can update your question to make it more clear what you are exactly trying to achieve. – Bart van der Drift May 01 '19 at 09:48
  • Problem is in this case: Thread 1 uses GetOrAdd, then lock value, then TryRemove. In this time Thread 3. uses GetOrAdd, taking value, but waiting lock from Thread 1. When lock from Thread 1 releases, Thread 3 lock removed value. In this time Thread 4 uses GetOrAdd, and creating new dictionary element (which not match with value taken by Thread 3). And we have 2 threads (Thread 3 and Thread 4) which working with same key. – Александр Бахматов May 01 '19 at 10:29
  • I think instead of describing the problem, you could better describe the requirements of what you are trying to achieve. When are items added to the dictionary? Can there be multiple items with the same key? Can items be processed multiple times? Or should they be deleted after being processed? – Bart van der Drift May 01 '19 at 10:47
  • Items adding to dictionary before lock. Cannot be multiple items with same key. Items can be processed multiple times, but not same key in same time. They should be deleted after execution of thread. – Александр Бахматов May 01 '19 at 11:20
  • maybe me need just use in lock Interlocked.CompareExchange on locked value and read value in dictionary? – Александр Бахматов May 01 '19 at 14:07