假设你有一个在后台线程上运行的简单操作。你想提供一种取消这个操作的方式,因此你创建了一个布尔标志,并从取消按钮的单击事件处理程序中将其设置为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变量标记为volatile。这是必要的吗?有两种理论。
1)因为它是一个简单的内置类型(在.NET中访问内置类型是原子的),我们只在一个地方写入并在后台线程上读取,所以不需要锁定或标记为volatile。 2)您应该将其标记为volatile,因为如果不这样做,编译器可能会优化掉while循环中的读取,因为它认为没有任何东西能够修改该值。
哪种技术是正确的?(为什么?)
【编辑:看来这里有两个明确定义和对立的观点。我正在寻找一个明确的答案,请尽可能在回答中附上您的理由和引用来源。】
volatile
或者lock
(作为内存屏障)来避免 C++ 线程缓存一个值并忽略其他线程对该值的更改。具体请参考此链接:https://dev59.com/lHRB5IYBdhLWcg3w9Lvn#458193 - Marc Gravell