并发字典和线程

时间:2019-05-01 06:45:42

标签: c# multithreading thread-safety concurrentdictionary

我在IIS应用程序池中有一个WCF服务。 WCF服务的方法接收JSON中的某些数据,例如{“ object”:“ someobject”,“ payload”:[int key]}。
对于每个请求,我都运行新线程以使用key。
密钥添加到ConcurrentDictionary中,并锁定ConcurrentDictionary的值。
这样做的目的是:密钥的一个示例只能运行一次,例如:
线程1 -使用键1
运行 线程2 -使用键2
运行 线程3 -等待锁定线程1
但是,当我从ConcurrentDictionary中删除键时,另一个线程已经通过键获取了值并对其进行了处理。如何避免这种情况? 附近的线程处理程序示例

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
            {
            }
        }

在这种情况下,问题是:线程1使用GetOrAdd,然后锁定值,然后使用TryRemove。在这个时候,线程3使用GetOrAdd,获取值,但是等待线程1的锁。当线程1的锁释放时,线程3的锁删除了值。在这个时候,线程4使用GetOrAdd,并创建新的字典元素(与线程3的值不匹配)。并且我们有2个线程(线程3和线程4)使用相同的密钥。

1 个答案:

答案 0 :(得分:0)

TryRemove函数已经为您提供了默认对象(如果它在词典中尚不存在),因此您可以简单地这样做:

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
    {
    }
}