Lockfree Read value after Interlocked.Exchange?

喜你入骨 提交于 2021-02-08 06:49:55

问题


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();
    }
}

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

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?


回答1:


You are missing the point...

Unless you do:

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

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...

So:

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();
}

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.

So if you do:

private static int myuselessvolatilefieldthatcanbestatic;
private int thefieldiwanttoread;

and then

var useless = myuselessvolatilefieldthatcanbestatic;
var iwanttoknow = thefieldiwanttoread;

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

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
}

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




回答2:


If you want to read the latest available value, you should use something like Interlocked.CompareExchange(ref bar, null, null). Checking for null is just for satisfying CompareExchange signature (if bar is null, then it will set it to null). This will give you the latest value that was available among CPUs at the execution moment.



来源:https://stackoverflow.com/questions/29107314/lockfree-read-value-after-interlocked-exchange

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!