【问题标题】:Locks on ConcurrentDictionary values' properties锁定 ConcurrentDictionary 值的属性
【发布时间】:2017-05-03 21:37:01
【问题描述】:

想象一个 ConcurrentDictionary 存储 Foo 的集合。是否有必要担心 Foo 的 Bar 属性的线程安全(例如线程 1 在线程 2 设置值的同时获取 Bar 的值)?还是字典本身的并发性使属性线程安全?

//Bar with no lock
public class Foo
{
    public string Bar { get; set; }
}

//Bar with lock
public class Foo
{
    private readonly object barLocker = new object();
    private string bar;

    public string Bar
    {
        get
        {
            lock(barLocker)
            {
                return bar;
            }
        }
        set
        {
            lock(barLocker)
            {
                bar = value;
            }
        }
    }
}

【问题讨论】:

  • 没有人可以评论未显示的代码的功能。
  • 这是一个关于 ConcurrentDictionary 对象本身的问题,而不是任何具体的实现。
  • 只是因为您使用的线程安全容器对容器中对象的线程安全没有任何影响。从容器中检索对象后,您就有了一个对象
  • 不,您是在询问存储在字典中的对象,并询问使用它是否安全。在不知道对象、如何使用、如何使用字典以及所有其他相关上下文的情况下,没有人可以说这种用法是否合适。
  • 没有提及具体用法,因为这是关于 ConcurrentDictionary 本身以及它是否为其包含的对象的属性提供线程安全性的一般问题。

标签: c# thread-safety concurrentdictionary


【解决方案1】:

ConcurrentDictionary 的方法是线程安全的,但不会扩展到字典中项目的方法或属性。

这是一个用于演示的单元测试。它执行以下操作:

  • 创建一个由 40 个 1 和 0 组成的字符串。
  • 创建具有字符串属性的类并将其放入并发字典中。
  • 循环遍历第一个字符串中的所有字符,并将每个字符附加到字典中对象的属性中。

如果ConcurrentDictionary 使其中的对象成为线程安全的,那么新的字符串属性至少应该与原来的长度相同。

结果?测试偶尔会通过,但通常会失败。字符串属性的长度因测试而异,因为更新的属性不是线程安全的。

[TestClass]
public class ConcurrentDictionaryTests
{
    [TestMethod]
    public void DoesntMakeContentsThreadsafe()
    {
        var s = "1010101010101010101010101010101010101010";
        var dictionary = new ConcurrentDictionary<int, ClassWithProperty>();
        dictionary.TryAdd(1, new ClassWithProperty());
        Parallel.ForEach(s, c => dictionary[1].TheString += c);
        Assert.AreEqual(s.Length, dictionary[1].TheString.Length);
    }
}

public class ClassWithProperty
{
    public string TheString { get; set; }
}

另一种看待它的方式 - 如果将对象放入 ConcurrentDictionary 使其属性线程安全,那么对于大量多线程属性来说,这将是一个简单的修复。需要一个对象是线程安全的吗?只需将其放入ConcurrentDictionary

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-08-29
    • 2012-09-07
    • 1970-01-01
    • 2018-04-12
    • 1970-01-01
    • 2010-12-29
    • 1970-01-01
    相关资源
    最近更新 更多