混合锁和互锁操作安全吗?
-
10-10-2019 - |
题
我有一些代码必须是线程安全的,其行为类似于以下情况:
protected long m_RunningValue
protected long m_RunningCounter
protected object m_Lock = new object();
public long RunningValue { get { return Interlocked.Read(m_RunningValue); } }
public long RunningCounter { get { return Interlocked.Read(m_RunningCounter); } }
public void DoCalculation(int newValue, int newQuantity)
{
lock(m_Lock)
{
Interlocked.Add(ref m_RunningValueA, newValue);
Interlocked.Add(ref m_RunningCounter, newQuantity);
if(Interlocked.Read(ref newQuantity) == 0)
{
...m_RunningValue gets further modified here
}
}
}
计算必须锁定值和计数器或竞赛条件可能会影响(...)块,但是在读出时,它们根本不需要同步,即,如果计数器和价值在尝试之间的价值变化,则阅读两者,这对我来说是100%。
读取上的互锁是在那里进行64位值的线程安全读数。
混合互锁和像这样的锁吗?我已经在其他网页上阅读了混合它们是不安全的,但是我找不到澄清,如果这意味着将它们混合是引入微妙的错误的好方法,或者如果在系统级别上,则可能会损坏所涉及的数据结构。
所有这些互锁(64位.NET 4.0运行时)的成本是否完全击败了保存properting()方法周围读者作者锁定的目的?
解决方案
关于编辑版本,这是 不是 保证是线程安全。
考虑一个32位平台。这意味着必须在两个单独的操作中访问64位长值。
一个线程很有可能读取数字的前半部分,然后换掉CPU,后半部分在后面后面变化。现在,该线程具有完全无效的值。
文档 互锁。阅读 明确提及:
读取方法和64位超载的增量,减少和添加方法仅在System.Intptr长64位的系统上才真正原子。在其他系统上,这些方法相对于彼此而言是原子的,但与访问数据的其他手段相对。因此,要在32位系统上安全的线程, 任何访问 必须通过联锁班级的成员进行64位值。
(强调我的)
编辑:现在已经对其进行了编辑,看起来有些愚蠢,但是我将其留在这里,以指出,如果您在某些地方互锁而不是其他地方,那就毫无意义。
不隶属于 StackOverflow