我是否需要锁定或标记为挥发性在C#中访问一个简单的布尔标志是什么时候? [英] Do I need to lock or mark as volatile when accessing a simple boolean flag in C#?

查看:189
本文介绍了我是否需要锁定或标记为挥发性在C#中访问一个简单的布尔标志是什么时候?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

让我们只说你有一个简单的操作是在后台线程中运行。你想提供一种方式来取消该操作,所以你创建你的取消按钮单击事件处理程序设置为true布尔标志。

Lets just say you have a simple operation that runs on a background thread. You want to provide a way to cancel this operation so you create a boolean flag that you set to true from the click event handler of a cancel button.

private bool _cancelled;

private void CancelButton_Click(Object sender ClickEventArgs e)
{
    _cancelled = true;
}

现在你设置的GUI线程取消标志,但你从后台线程读取它。您是否需要访问布尔之前锁定?

Now you're setting the cancel flag from the GUI thread, but you're reading it from the background thread. Do you need to lock before accessing the bool?

您需要做的(显然锁定按钮单击事件处理程序太):

Would you need to do this (and obviously lock in the button click event handler too):

while(operationNotComplete)
{
    // Do complex operation

    lock(_lockObject)
    {
        if(_cancelled)
        {
            break;
        }
    }
}

或者是可以接受的做到这一点(无锁):

Or is it acceptable to do this (with no lock):

while(!_cancelled & operationNotComplete)
{
    // Do complex operation
}

或者有什么关于这标志着_cancelled变量波动。有必要吗?

Or what about marking the _cancelled variable as volatile. Is that necessary?

[我知道有BackgroundWorker的类,它的内置CancelAsync()方法,但我感兴趣的语义和使用锁定和螺纹变量访问这里,而不是具体的实施中,code只是一个例如。]

[I know there is the BackgroundWorker class with it's inbuilt CancelAsync() method, but I'm interested in the semantics and use of locking and threaded variable access here, not the specific implementation, the code is just an example.]

似乎有两种理论。

1),因为它是一个简单的内置类型(并获得内在的类型是原子在.NET),因为我们只写它在一个地方,只有阅读的后台线程没有必要锁定或标记为volatile。
2)你应该将其标记为挥发性的,因为如果你没有编译器可能会因为它认为没有修改的价值它能够优化了阅读while循环。

1) Because it is a simple inbuilt type (and access to inbuilt types is atomic in .net) and because we are only writing to it in one place and only reading on the background thread there is no need to lock or mark as volatile.
2) You should mark it as volatile because if you don't the compiler may optimise out the read in the while loop because it thinks nothing it capable of modifying the value.

这是正确的方法? (为什么?)

Which is the correct technique? (And why?)

推荐答案

首先,线程是棘手的;-p

Firstly, threading is tricky ;-p

是的,尽管所有的传言相反,它的需要的或者的使用锁定挥发性(但不能同时)访问时,布尔从多个线程。

Yes, despite all the rumours to the contrary, it is required to either use lock or volatile (but not both) when accessing a bool from multiple threads.

对于简单类型和访问,如出口标志(布尔),那么挥发性就足够了 - 这保证该线程不缓存在他们的寄存器(意思是:一个线程永远不会看到更新)值

For simple types and access such as an exit flag (bool), then volatile is sufficient - this ensures that threads don't cache the value in their registers (meaning: one of the threads never sees updates).

对于较大的值(其中,原子是一个问题),或者你想同步操作的的的(一个典型的例子是,如果不存在,并添加字典中访问),一个锁定更通用。这作为一个内存屏障,静得让你的线程安全的,但提供其他功能,如脉冲/等待。请注意,你不应该在一个数值类型或字符串使用锁定;也不键入;最好的选择是有自己的锁定对象的字段。(只读对象SYNCLOCK =新的对象(); ),在此锁定

For larger values (where atomicity is an issue), or where you want to synchronize a sequence of operations (a typical example being "if not exists and add" dictionary access), a lock is more versatile. This acts as a memory-barrier, so still gives you the thread safety, but provides other features such as pulse/wait. Note that you shouldn't use a lock on a value-type or a string; nor Type or this; the best option is to have your own locking object as a field (readonly object syncLock = new object();) and lock on this.

有关如何厉害它打破了一个例子(即循环永远),如果你不同步 - <一个href="http://stackoverflow.com/questions/458173/can-a-c-thread-really-cache-a-value-and-ignore-changes-to-that-value-on-other-th/458193#458193">see这里。

For an example of how badly it breaks (i.e. looping forever) if you don't synchronize - see here.

要跨越多个程序,操作系统原始像互斥 * ResetEvent 也可能是有用的,但是这是矫枉过正一个exe文件。

To span multiple programs, an OS primitive like a Mutex or *ResetEvent may also be useful, but this is overkill for a single exe.

这篇关于我是否需要锁定或标记为挥发性在C#中访问一个简单的布尔标志是什么时候?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆