Lockfree 读取 Interlocked.Exchange 后的值? [英] Lockfree Read value after Interlocked.Exchange?

查看:57
本文介绍了Lockfree 读取 Interlocked.Exchange 后的值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我们有一个这样的类:

Lets say we have a class like so:

public class Foo
{
     private Bar bar = new Bar();

    public void DoStuffInThread1()
    {
        var old = Interlocked.Exchange(ref bar,new Bar());
        //do things with old
        //everything is fine here, I'm sure I have the previous bar value
    }

    public void OtherStuffFromThread2()
    {
        //how do I ensure that I have the latest bar ref here
        //considering mem cahces etc
        bar.Something();
    }
}

假设我们有两个线程,一个在 DoStuffInThread1 上运行,另一个在 OtherStuffFromThread2 上运行.

And lets say we have two threads, one operating on DoStuffInThread1 and another on OtherStuffFromThread2.

如何确保 thread2 始终看到最新的 bar?volatile 没有帮助.我不想要老式的锁.必须有一种方法以某种方式读取带有 mem 屏障/互锁的 bar 的正确值?

How do I ensure that thread2 always sees the latest bar? volatile doesn't help. and I don't want old school locks. There has to be a way to read the correct value of bar with mem barriers/interlocked somehow?

推荐答案

你没有抓住重点...

除非你这样做:

public void OtherStuffFromThread2()
{
    while (true)
    {
        //how do I ensure that I have the latest bar ref here
        //considering mem cahces etc
        bar.Something();
    }
}

这是不太可能的事情,几乎您可以在 OtherStuffFromThread2() 上使用的所有方法来等待线程 1 准备就绪都会导致隐式内存屏障...参见例如 内存屏障生成器 一些导致内存屏障的构造...

That is something quite improbable, nearly every method you could use on OtherStuffFromThread2() to wait for thread1 to be ready will cause an implicit memorybarrier... See for example Memory barrier generators some constructs that cause memorybarriers...

所以:

public void OtherStuffFromThread2()
{
    Thread.Sleep(Timespan.FromMinutes(1));
    // Implicit MemoryBarrier here :-)

    //how do I ensure that I have the latest bar ref here
    //considering mem cahces etc
    bar.Something();
}

如果你真的想读取一个变量的值,你可以先读取一个 volatile 变量,然后再读取你的变量(或者读取同一个 volatile 变量两次).为什么?因为易失性读取会导致获取语义,这意味着它无法在后续内存操作中重新排序,请参阅 https://msdn.microsoft.com/en-us/library/aa645755(v=vs.71).aspx :

If you really want to read the value of a variable, you can read a volatile variable and then read your variable (or read the same volatile variable twice). Why? because a volatile read causes an acquire semantics, which means it can’t be reordered with subsequent memory operations, see https://msdn.microsoft.com/en-us/library/aa645755(v=vs.71).aspx :

对易失性字段的读取称为易失性读取.易失性读取具有获取语义";也就是说,它保证在指令序列中发生在它之后的任何内存引用之前发生.

A read of a volatile field is called a volatile read. A volatile read has "acquire semantics"; that is, it is guaranteed to occur prior to any references to memory that occur after it in the instruction sequence.

如果你这样做:

private static int myuselessvolatilefieldthatcanbestatic;
private int thefieldiwanttoread;

然后

var useless = myuselessvolatilefieldthatcanbestatic;
var iwanttoknow = thefieldiwanttoread;

thefieldiwanttoread 将包含一个值,该值将在 myuselessvolatilefieldthatcanbestatic 的新读取完成后 读取.

The thefieldiwanttoread will contain a value that will be read after a new read to myuselessvolatilefieldthatcanbestatic has been done.

请注意,如果没有同步原语,将很难知道 myuselessvolatilefieldthatcanbestatic 何时完成 :-),但是:

Note that without a synchronization primitive, it will be difficult to know when the myuselessvolatilefieldthatcanbestatic will be done :-), but:

while (true)
{
    var useless = myuselessvolatilefieldthatcanbestatic;
    var iwanttoknow = thefieldiwanttoread;
    // Some code goes here
}

现在至少你可以使用你的 while (true) :-)

Now at least you can use your while (true) :-)

这篇关于Lockfree 读取 Interlocked.Exchange 后的值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆