我想在 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
);
答案 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#?