在多CPU机器上运行的多线程程序中,我需要使用易失性读/写来访问共享状态(下面的示例代码中的_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.
谢谢你的帮助.
我想您可能误解了volatile
关键字的使用(无论是我或是,有人请随时纠正我).该volatile
关键字保证从多个线程变量本身的价值get和set操作会一直处理同一个副本.例如,如果我有一个bool
指示状态,那么在一个线程中设置它将使新值立即可用于另一个.
但是,您永远不会更改变量的值(在本例中为引用).你所做的只是操纵参考指向的内存区域.将其声明为volatile readonly
(如果我的理解是合理的,通过永不允许设置来破坏volatile的目的)将不会对被操纵的实际数据(后端存储Dictionary<>
)产生任何影响.
所有这一切,在这种情况下你真的需要使用锁.你的危险超出了"脏读"的前景(意味着你所读的内容在某些时候是有效的)进入真正未知的领域.正如乔恩所说,在你试图走上无锁编码的道路之前,你确实需要证明锁定会产生不可接受的性能.否则,这是过早优化的缩影.
如果您开始在其上调用方法,我认为 volatile 不能替代锁定。您保证线程 A 和线程 B 看到相同的字典副本,但您仍然可以同时访问该字典。您可以使用多模式锁来增加并发性。参见ReaderWriterLockSlim
例如。
表示用于管理对资源的访问的锁,允许多个线程进行读取或进行独占访问进行写入。