Interlocked在所有线程中提供可见性吗?

32 浏览
0 Comments

Interlocked在所有线程中提供可见性吗?

假设我有一个变量"counter",有几个线程通过使用Interlocked来访问和设置"counter"的值,即:

int value = Interlocked.Increment(ref counter);

int value = Interlocked.Decrement(ref counter);

我可以假设,Interlocked所做的更改将在所有线程中可见吗?

如果不是,我应该怎么做才能使所有线程同步该变量?

编辑:有人建议我使用volatile。但是当我将"counter"设置为volatile时,编译器会警告"对volatile字段的引用将不被视为volatile"。

当我阅读在线帮助时,它说:"通常不应该使用ref或out参数传递volatile字段"。

0
0 Comments

InterlockedIncrement/Decrement操作在x86 CPU上(x86的lock add/dec)会自动创建内存屏障(memory barrier),这给所有线程提供了可见性(即所有线程都可以看到其更新,就像顺序内存一致性一样)。内存屏障使得所有待处理的内存加载/存储操作得以完成。虽然C#和Java(以及一些C / C ++编译器)强制使用volatile关键字来创建内存屏障,但它与这个问题无关。但是,Interlocked操作已经通过CPU实现了内存屏障。

然而,仅有硬件层面的可见性并不足以暗示“程序”层面的可见性。在多线程编程中,我们经常需要确保在一个线程中的操作对其他线程是可见的,而不仅仅是在CPU层面上可见。这就是为什么需要使用内存屏障和其他同步机制来确保线程间的可见性。

有时,我们可能需要在程序中使用Interlocked操作来实现原子操作,同时确保线程间的可见性。Interlocked操作已经提供了内存屏障,但仅限于特定的操作(如增量、递减、交换等)。这意味着,使用Interlocked操作进行原子操作时,我们可以确保其他线程在某个操作完成后才能看到更新的值。

然而,对于其他类型的操作,仅仅使用Interlocked操作可能无法保证线程间的可见性。因此,在编写多线程程序时,我们应该考虑使用其他同步机制,如锁、信号量、事件等,以确保线程间的可见性。

总之,Interlocked操作提供了一种保证特定操作的原子性和线程间可见性的机制。但在程序中的其他操作中,我们仍然需要使用其他同步机制来确保线程间的可见性。

0
0 Comments

在多线程编程中,有时候我们需要确保变量在所有线程中的可见性。在上述内容中,提到了一个问题:使用Interlocked操作修改变量值时,是否会在所有线程中保持可见性。如果不加额外的处理,可能会导致变量在某些线程中不可见,从而引发问题。

解决这个问题的方法是将变量声明为volatile,这样可以告诉编译器变量可能会发生改变,从而保证在所有线程中的可见性。如果直接读取counter,则需要将其声明为volatile。否则,编译器没有理由相信counter会发生改变,因为Interlocked操作可能在编译器无法感知的代码中。

除了使用volatile关键字外,还可以使用Volatile.Read方法来确保变量的可见性,这可能更适合一些情况。

0
0 Comments

Interlocked类是一个用于在多个线程中操作共享变量的工具类。它提供了一些原子操作,可以确保在多个线程中对变量的操作是同步的。然而,有时候对Interlocked进行的修改并不一定会在所有线程中可见。

当我们仅仅读取一个变量时,不使用Interlocked的话,在其他线程中并不能保证读取到的值是最新的,除非我们将该变量标记为volatile。但是,使用volatile关键字会引发一些令人烦恼的警告。

作为一种替代的方法,我们可以使用另一个Interlocked操作来读取变量的值。这样,在所有线程中都能看到更新后的值:

int readvalue = Interlocked.CompareExchange(ref counter, 0, 0);

这个方法会返回读取到的值,并且如果它的值是0,则将其与0进行交换。

这样做的动机是,警告提示有些不对劲;结合使用volatile和Interlocked并不是预期的做法。

更新:似乎还有另一种在不使用volatile的情况下可靠读取32位变量的方法,就是使用Thread.VolatileRead,正如这个答案中建议的那样。还有一些证据表明,我对使用Interlocked进行32位读取的理解是错误的,例如这个Connect问题,不过我想知道这个区别是否有点学究味道。

我的真实意思是:不要把这个回答作为唯一的参考;我对此有些怀疑。

0