【问题标题】:ConcurrentDictionary and threads并发字典和线程
【发布时间】:2019-05-01 06:45:41
【问题描述】:

我在 IIS 应用程序池中有 WCF 服务。 WCF 服务的方法接收一些 JSON 格式的数据,例如 {"object": "someobject", "payload": [int key]}。
对于每个请求,我都会运行新线程来处理密钥。
键正在添加到 ConcurrentDictionary 并锁定 ConcurrentDictionary 的值。
这样做的目的是:一次只能运行一个 key 示例,例如:
Thread 1-Running with key 1
Thread 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)使用相同的键。

【问题讨论】:

  • 这更多的是关于你的解决方案(算法)而不是线程安全。您可以使用锁内的 ContainsKey 解决第一个问题。但是,当可以重新添加密钥时,您必须在此处更好地指定逻辑。
  • @HenkHolterman 如何检查锁内的值与键不存在?当键移除时,另一个线程(例如线程 4)在字典中添加新值
  • 嗯,你有字典,你有钥匙......你可以使用!
  • 对不起,我不明白
  • 我已经回答了。

标签: c# multithreading thread-safety concurrentdictionary


【解决方案1】:

如果字典中不存在默认对象,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
    {
    }
}

【讨论】:

  • 它如何帮助我通过钥匙锁定元素?
  • 您从字典中删除了键,因此不再需要锁定元素,因为没有其他线程能够从字典中获取它。
  • 但是第一个线程,什么要访问对象,不能通过 TryRemove 获取对象,对吧?
  • 是的,TryRemove 将返回已从字典中删除的对象。因为该方法是原子的,所以在元素被删除之前只有一个线程能够访问该元素。请在此处查看更多信息:docs.microsoft.com/en-us/dotnet/api/…
  • 如何帮助第一个线程向字典中添加元素?我需要比另一个线程等待直到锁定被释放,因为它就像对字典的请求队列,具有相同键的下一个线程需要等待,而前一个工作人员正在工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-11-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-01
相关资源
最近更新 更多