假设您有一个在后台线程上运行的简单操作。您希望提供一种方法来取消此操作,因此您创建一个布尔标志,并从取消按钮的单击事件处理程序将其设置为 true。
private bool _cancelled;
private void CancelButton_Click(Object sender ClickEventArgs e)
{
_cancelled = true;
}
现在您正在从 GUI 线程设置取消标志,但您正在从后台线程读取它。访问布尔值之前需要锁定吗?
您是否需要这样做(显然也锁定按钮单击事件处理程序):
while(operationNotComplete)
{
// Do complex operation
lock(_lockObject)
{
if(_cancelled)
{
break;
}
}
}
或者这样做是否可以接受(没有锁):
while(!_cancelled & operationNotComplete)
{
// Do complex operation
}
或者将 _cancelled 变量标记为易失性怎么样。有必要吗?
[我知道有一个带有内置CancelAsync()方法的BackgroundWorker类,但我对这里锁定和线程变量访问的语义和使用感兴趣,而不是具体的实现,代码只是一个例子。]
似乎有两种理论。
1)因为它是一个简单的内置类型(并且在.net中对内置类型的访问是原子的)并且因为我们只在一个地方写入它并且只在后台线程上读取,所以不需要锁定或标记为易失性。
2)您应该将其标记为易失性,因为如果不这样做,编译器可能会优化 while 循环中的读取,因为它认为没有任何东西能够修改该值。
哪种技术是正确的? (为什么?)
[编辑:对此似乎存在两种明确定义且对立的思想流派。我正在寻找对此的明确答案,因此如果可能的话,请发表您的理由并在您的答案中引用您的来源。]