2015-04-02 70 views
6

我很困惑这个问题 - 读/切换布尔值是否线程安全。C#和线程安全的bool

// case one, nothing 
    private bool v1; 
    public bool V1 { get { return v1; } set { v1 = value; } } 

    // case two, with Interlocked on set 
    private int v2; 
    public int V2 { get { return v2; } set { Interlocked.Exchange(ref v2, value); } } 

    // case three, with lock on set 
    private object fieldLock = new object(); 
    private bool v3; 
    public bool V3 { get { return v3; } set { lock (fieldLock) v3 = value; } } 

他们都是线程安全的吗?

编辑

从我读(click)布尔的原子并不保证它是线程安全的。请问volatile型的帮助?

+1

这些都不是线程安全的。调用getter的线程将始终读取陈旧值。它有多陈旧取决于处理器和优化器。从几纳秒到无穷大。吸气剂也需要同步。或者你可以使用ManualResetEvent/Slim。 – 2015-04-02 12:26:51

+0

@ Ksv3n * Assignement总是一个原子操作*假,32位程序的“长”(64位)分配不是原子的。 – xanatos 2015-04-02 13:00:24

+0

@HansPassant一个getter可以读取一个旧值,这是可以理解的。但是,它怎么会持续到无穷?使用锁将使它读取*正确*值 - 重读它,就好像它是不稳定的?我不认为它是这样工作的,我对你说的话感到困惑。我认为一旦没有人在写东西,吸气剂就会正常工作。 – 2015-04-02 13:40:58

回答

12

不,不是所有的都是线程安全的。

第一种情况实际上并不完全是线程安全的,或者更好的说法 - 它根本不是线程安全的。即使布尔操作是原子操作,变量值也可以存储在缓存中,因此,如同多核CPU一样,每个核心都有它自己的缓存,可能会损坏值。编译器和CPU可以执行一些内部优化,包括指令重新排序,这可能会对程序的逻辑造成不利影响。

您可以添加volatile关键字,以通知编译器该字段在多线程环境中使用。它将解决高速缓存和指令重新排序问题,但不会为您提供真正的“线程安全”代码(因为写入操作仍然不会同步)。另外volatile不能应用于局部变量。

因此,在处理多线程时,您总是必须使用一些线程同步技术来处理有价值的资源。

欲了解更多信息 - 请阅读this答案,其中有一些更深入的解释不同的技术。 (例如大约有int,但实际上并不重要,它描述了一般方法。)

+3

*值可能被破坏*否,值不能被破坏(如在“转换非法/未定义的值”)。你可能会陈旧(“旧”)值。 – xanatos 2015-04-02 12:58:38

+0

我的意思是“腐败”的方式“不是一个,它应该或你期望它是”。绝对不是在内存腐败的意义上的损坏:) – Yura 2015-04-02 15:26:03