C#中的非阻塞线程安全布尔标志

时间:2017-10-11 21:50:00

标签: c# multithreading

我想在 32位和64位系统上创建既线程安全又无阻塞的布尔标志。该解决方案是否满足这两个要求?如果没有,会是什么?

public bool Flag {
    get {
        return Interlocked.Read( ref _flag ) == 1;
    }
    set {
        if ( value ) {
            // set flag to "true" if it's false
            Interlocked.CompareExchange( ref _flag, 1, 0 );
        }
        else {
            // set flag to "false" if it's true
            Interlocked.CompareExchange( ref _flag, 0, 1 );
        }
    }
}
private Int32 _flag;

(已编辑)使用Int32通过。 @ M.kazemAkhgary

示例: 3个计时器,每个计时器都有故意重叠的刻度间隔。 2个计时器回调正在读取标志。 1个定时器回调读写标志。

// Inline function
void Callback( object msg ) {
    if ( Flag ) Debug.WriteLine( (string) msg );
}

// Checks Flag
var timer1 = new Timer( 
    Callback,
    "Tick", // callback arg
    0,      // start timer now
    100     // callback interval ms
);

// Checks Flag
var timer2 = new Timer( 
    Callback, 
    "Tock", // callback arg
    0,      // start timer now
    20      // callback interval ms
);

// Toggles Flag every second
var timer3 = new Timer( 
    _ => {
        Flag = !Flag;
    }, 
    null, // callback arg
    0,    // start timer now
    1000  // callback interval ms
);

1 个答案:

答案 0 :(得分:0)

您已关闭,但请检查CompareExchange上的MSDN文档:https://msdn.microsoft.com/en-us/library/801kt583(v=vs.110).aspx

首先,您可以使用int而不是Int64来保持标志的状态,读取int是一个原子操作。只在32位机器上读取Int64不是原子的。

你的代码应该是这样的:(我还没有测试过它)

public bool Flag {
get {
    return _flag == 1; // no Interlocked.Read here, reading an int from memory is an atomic operation
}
set {
    if ( value ) {
        // set flag to "true" if it's false

        int newFlagValue = 1;
        int initialFlagValue;
        do {
        // Save the current flag value in a local variable.
        initialFlagValue = _flag; 
        } while (initialFlagValue != Interlocked.CompareExchange(
            ref _flag, newFlagValue, initialFlagValue));            
    }
    else {
        // similar as above.
    }
}
}
private int _flag;

更新

关于volatile的使用,有很多错过用法,所以我会尽量避免使用它。查看这篇精彩帖子: When should the volatile keyword be used in C#?