Reading an int that's updated by Interlocked on other threads

前端 未结 4 1514
终归单人心
终归单人心 2020-12-05 00:21

(This is a repeat of: How to correctly read an Interlocked.Increment'ed int field? but, after reading the answers and comments, I\'m still not sure of the right answer.)

4条回答
  •  暗喜
    暗喜 (楼主)
    2020-12-05 00:51

    Well, any value you read will always be somewhat stale as Hans Passant said. You can only control a guarantee that other shared values are consistent with the one you've just read using memory fences in the middle of code reading several shared values without locks (ie: are at the same degree of "staleness")

    Fences also have the effect of defeating some compiler optimizations and reordering thus preventing unexpected behavior in release mode on different platforms.

    Thread.VolatileRead will cause a full memory fence to be emitted so that no reads or writes can be reordered around your read of the int (in the method that's reading it). Obviously if you're only reading a single shared value (and you're not reading something else shared and the order and consistency of them both is important), then it may not seem necessary...

    But I think that you will need it anyway to defeat some optimizations by the compiler or CPU so that you don't get the read more "stale" than necessary.

    A dummy Interlocked.CompareExchange will do the same thing as Thread.VolatileRead (full fence and optimization defeating behavior).

    There is a pattern followed in the framework used by CancellationTokenSource http://referencesource.microsoft.com/#mscorlib/system/threading/CancellationTokenSource.cs#64

    //m_state uses the pattern "volatile int32 reads, with cmpxch writes" which is safe for updates and cannot suffer torn reads. 
    private volatile int m_state;
    
    public bool IsCancellationRequested
    {
        get { return m_state >= NOTIFYING; } 
    }
    
    // ....
    if (Interlocked.CompareExchange(ref m_state, NOTIFYING, NOT_CANCELED) == NOT_CANCELED) {
    }
    // ....
    

    The volatile keyword has the effect of emitting a "half" fence. (ie: it blocks reads/writes from being moved before the read to it, and blocks reads/writes from being moved after the write to it).

提交回复
热议问题