c# - .NET4.0 : Thread-Safe Manner of Updating A Dictionary and Its Values

标签 c# multithreading .net-4.0

我有一个要安全更新的静态词典。最初,字典是空的,但在应用程序的生命周期中,它会添加新的值。此外,整数值将充当可以递增和递减的单独计数器。

private static Dictionary<string, int> foo = new Dictionary<string, int>();

public static void Add(string bar)
{
    if (!foo.ContainsKey(bar))
        foo.Add(bar, 0);

    foo[bar] = foo[bar] + 1;
}


public static void Remove(string bar)
{
    if (foo.ContainsKey(bar))
    {
        if (foo[bar] > 0)
            foo[bar] = foo[bar] - 1;
    }
}

我一直在阅读 Interlocked class作为提供线程安全的一种方式,看起来这可能是我可以使用的东西:

public static void Add(string bar)
{
    if (!foo.ContainsKey(bar))
        foo.Add(bar, 0);

    Interlocked.Increment(ref foo[bar]);
}


public static void Remove(string bar)
{
    if (foo.ContainsKey(bar))
    {
        if (foo[bar] > 0)
            Interlocked.Decrement(ref foo[bar]);
    }
}

但是,我的直觉是,当我实际向字典中添加新项目时,这不会解决问题,因此立即想到锁定:

private static Dictionary<string, int> foo = new Dictionary<string, int>();
private static object myLock = new object();

public static void Add(string bar)
{
    lock(myLock)
    {
        if (!foo.ContainsKey(bar))
            foo.Add(bar, 0);

        Interlocked.Increment(ref foo[bar]);
    }
}


public static void Remove(string bar)
{
    lock(myLock)
    {
        if (foo.ContainsKey(bar))
        {
            if (foo[bar] > 0)
                Interlocked.Decrement(ref foo[bar]);
        }
    }
}

这种方法是否理想,甚至是正确的?可以改进吗?我离题了吗?

最佳答案

lock是好的(而且是必要的;你怀疑 Interlocked 是不够的是对的)但是一旦你这样做了 Interlocked.IncrementInterlocked.Decrement是不必要的。访问 Dictionary<TKey, TValue> 的问题来自多个线程的是一个线程可以触发内部哈希表的重建,然后该线程在重建过程中被换出另一个线程,现在出现并添加到字典中,对字典的内部结构造成严重破坏。

此外,您的实现很好,因为您 lockprivate 上对象而不是 this .作为chibacity指出,这lock对象应该是 readonly虽然。

请注意不要自欺欺人地认为您现在已经使字典在多线程场景中无懈可击。例如,可能会发生以下情况:

Thread 1 looks up string "Hello, World!" in the dictionary, receives back the count 1.

Thread 1 is swapped out for Thread 2.

Thread 2 calls remove with key "Hello, World!" setting the count to 0.

Thread 2 is swapped out for Thread 1.

Thread 1 now thinks that the count is 1 but it is actually 0.

最后,在 .NET 4.0 中,您应该考虑使用 ConcurrentDictionary<TKey, TValue> .请注意,这有效地消除了 lock 的需要。在字典上调用实例方法时,但它并没有消除上述情况的发生。

关于c# - .NET4.0 : Thread-Safe Manner of Updating A Dictionary and Its Values,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4234049/

相关文章:

c# - 2 级联接 LINQ

c# - 如果只有一个元素,将 List<T> 转换为 T 项?

c# - Neo4j 关系写入性能与 Neo4j.Driver.V1

java - 使用 Java 锁时出现竞争条件的可能性

java - 线程在过载流量下如何以及为何被中断

c# - BindingSource.ResetBindings 不工作,除非 "true"通过

c# - Automapper 继承的源和目标

c# - 在 WebBrowser 中禁用 F5

c - 如何改进以下检查数字是否为素数的程序的 C 实现?

c# - 如何将 IEnumerable<Task<T>> 转换为 IObservable<T>