锁定ConcurrentDictionary值'属性

时间:2017-05-03 21:37:02

标签: c# thread-safety concurrentdictionary

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

//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;
            }
        }
    }
}

1 个答案:

答案 0 :(得分: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