在C#中使用volatile(Thread.VolatileRead/Thread.VolatileWrite)

8 c# multithreading

在多CP​​U机器上运行的多线程程序中,我需要使用易失性读/写来访问共享状态(下面的示例代码中的_data)以确保正确性.

换句话说,可以在cpu上缓存堆对象吗?

使用下面的示例并假设多线程将访问GetValue和Add方法,我需要ThreadA能够添加数据(使用Add方法)和ThreadB能够立即查看/获取添加的数据(使用GetValue方法) ).那么我需要向_data添加易失性读/写以确保这一点吗?基本上我不想添加要在ThreadA的cpu上缓存的数据.

/我不是锁定(强制独占线程访问),因为代码需要超快,我不从_data中删除任何数据,所以我不需要锁定_data.

谢谢.

****更新****************************

显然你们认为使用这个例子无锁是不好的主意.但是我可以在这里面对哪些副作用或例外?

如果1个线程正在迭代read值而另一个线程正在迭代update的值,那么Dictionary类型会抛出异常吗?或者我只会遇到"脏读"(在我的情况下会没问题)?

****结束更新****************************

public sealed class Data
{
    private volatile readonly Dictionary<string, double> _data = new Dictionary<string, double>();

    public double GetVaule(string key)
    {
        double value;
        if (!_data.TryGetValue(key, out value))
        {
            throw new ArgumentException(string.Format("Key {0} does not exist.", key));
        }
        return value;
    }

    public void Add(string key, double value)
    {
        _data.Add(key, value);
    }

    public void Clear()
    {
        _data.Clear();
    }
}
Run Code Online (Sandbox Code Playgroud)

谢谢你的回复.关于锁,这些方法几乎经常被多个线程调用,所以我的问题是有争议的锁而不是实际的锁操作.

所以我的问题是关于cpu缓存,可以将堆对象(_data实例字段)缓存在cpu上吗?我是否需要使用易失性读/写访问_data字段?

/另外,我坚持使用.Net 2.0.

谢谢你的帮助.

Jon*_*eet 16

MSDN文档Dictionary<TKey, TValue>说,它是多个安全的读者,但他们不给了"一个作家,多个读者"保证一些其他类的功能.简而言之,我不会这样做.

你说你正在避免锁定,因为你需要代码"超快" - 你试过锁定以查看开销是多少?无可争议的锁是非常便宜的,当锁被争议时,你会从增加的安全性中受益.在决定担心无锁解决方案的并发问题之前,我肯定会对此进行广泛的分析.ReaderWriterLockSlim如果你真的有多个读者可能会有用,但听起来你有一个读者和一个单独的作者,至少在目前 - 在这种情况下简单的锁定会更容易.


Ada*_*son 6

我想您可能误解了volatile关键字的使用(无论是我或是,有人请随时纠正我).该volatile关键字保证从多个线程变量本身的价值get和set操作会一直处理同一个副本.例如,如果我有一个bool指示状态,那么在一个线程中设置它将使新值立即可用于另一个.

但是,您永远不会更改变量的值(在本例中为引用).你所做的只是操纵参考指向的内存区域.将其声明为volatile readonly(如果我的理解是合理的,通过永不允许设置来破坏volatile的目的)将不会对被操纵的实际数据(后端存储Dictionary<>)产生任何影响.

所有这一切,在这种情况下你真的需要使用锁.你的危险超出了"脏读"的前景(意味着你所读的内容在某些时候是有效的)进入真正未知的领域.正如乔恩所说,在你试图走上无锁编码的道路之前,你确实需要证明锁定会产生不可接受的性能.否则,这是过早优化的缩影.


Eug*_*ota 2

如果您开始在其上调用方法,我认为 volatile 不能替代锁定。您保证线程 A 和线程 B 看到相同的字典副本,但您仍然可以同时访问该字典。您可以使用多模式锁来增加并发性。参见ReaderWriterLockSlim例如。

表示用于管理对资源的访问的锁,允许多个线程进行读取或进行独占访问进行写入。