如何正确读取Interlocked.Increment'ed int字段?

假设我有一个非易失性的int字段和一个Interlocked.Increment它的线程。 另一个线程是否可以直接安全地读取它,或者读取是否需要互锁?

我以前认为我必须使用一个互锁的读取来保证我看到当前的值,毕竟这个字段是不稳定的。 我一直在使用Interlocked.CompareExchange(int, 0, 0)来实现。

然而,我已经偶然发现了这个答案 ,这表明实际上,普通读取总是会看到Interlocked.Increment ed值的当前版本,由于int读取已经是primefaces的,所以不需要做任何特殊的事情。 我还发现了一个请求,微软拒绝了Interlocked.Read(ref int)的请求 ,并进一步暗示这是完全多余的。

那么我能否真正安全地读取这种没有Interlockedint域的最新值?

如果你想保证另一个线程将读取最新的值,你必须使用Thread.VolatileRead() 。 (*)

读取操作本身是primefaces的,所以不会产生任何问题,但是没有易失性的读取,您可能会从caching中获得旧的值,或者编译器可能会优化您的代码并完全消除读取操作。 从编译器的angular度来看,代码在单线程环境下工作就足够了。 易失性操作和内存屏障被用来限制编译器对代码进行优化和重新sorting的能力。

有几个参与者可以改变代码:编译器,JIT编译器和CPU。 它们中的哪一个显示你的代码被破坏并不重要。 唯一重要的是.NET内存模型,因为它指定了所有参与者必须遵守的规则。

(*) Thread.VolatileRead()并不真的获得最新的值。 它将读取值并在读取之后添加内存屏障。 第一个易失性读取可能获得caching值,但第二个将获得更新值,因为第一个易失性读取的内存屏障在必要时强制更新caching。 在实践中,这些细节在编写代码时没有什么重要性。

这是一个元问题,但是关于使用Interlocked.CompareExchange(ref value, 0, 0) (忽略读取时难以理解的明显缺点Interlocked.CompareExchange(ref value, 0, 0)一个好方面是它可以工作,不pipe是int还是long 。 确实int读取总是primefaces的,但long读取不是也可能不是,这取决于体系结构。 不幸的是, Interlocked.Read(ref value)只适用于valuetypes为long

考虑一下你从int字段开始的情况,这使得不可能使用Interlocked.Read() ,所以你会直接读取值,因为这是primefaces无论如何。 然而,在开发之后,你或者其他人决定需要很long – 编译器不会警告你,但现在你可能会有一个微妙的错误:读访问不能保证是primefaces了。 我发现使用Interlocked.CompareExchange()这里最好的select; 根据底层的处理器指令,速度可能会变慢,但从长远来看,这是更安全的。 我不太了解Thread.VolatileRead()的内部, 这个用例可能是“更好”的,因为它提供了更多的签名。

我不会尝试在一个循环或任何紧密的方法调用中直接读取值(即没有任何上述机制),因为即使写入是易失性和/或内存障碍,也没有任何东西告诉编译器:字段的值实际上可以在两个读取之间改变。 所以,该字段应该是volatile或者应该使用任何给定的结构。

我的两分钱

你是正确的,你不需要一个特殊的指令来自动读取一个32位的整数,但是,这意味着你将得到“整体”的价值(即你不会得到一部分写作,另一部分 )。 你没有保证,一旦你阅读它的价值将不会改变。

在这一点上,您需要决定是否需要使用其他同步方法来控制访问,比如说如果使用此值从数组中读取成员等。


简而言之, primefaces性确保操作完全且不可分割。 给定A包含N步骤的操作A ,如果你在A之后进行了操作,那么可以确定所有N步骤都是在并发操作之外发生的。

如果你有两个执行primefaces操作A线程,你可以保证你只能看到两个线程之一完整结果。 如果你想协调线程,可以使用primefaces操作来创build所需的同步。 但是primefaces操作本身并不提供更高级别的同步。 Interlocked系列的方法可用于提供一些基本的primefaces操作。

同步是一种更广泛的并发控制,通常是围绕primefaces操作构build的。 大多数处理器都包含内存屏障,可以确保所有caching行都被刷新,并且拥有一致的内存视图。 易失性读取是确保对给定内存位置的一致访问的一种方式。

虽然不能立即适用于您的问题,但阅读关于数据库的ACID(primefaces性,一致性,隔离性和持久性)可能会帮助您理解术语。

是的,你所读的一切都是正确的。 Interlocked.Increment被devise为使正常读取在对字段进行更改时不会是错误的。 阅读一个领域并不危险,写一个领域是。