'volatile' 关键字在 C# 中仍然无效吗? [英] Is the 'volatile' keyword still broken in C#?

查看:112
本文介绍了'volatile' 关键字在 C# 中仍然无效吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Joe Albahari 有一个关于多线程的很棒的系列,这是必读的,并且应该牢记在心任何使用 C# 多线程的人.

Joe Albahari has a great series on multithreading that's a must read and should be known by heart for anyone doing C# multithreading.

然而,在第 4 部分中,他提到了 volatile 的问题:

In part 4 however he mentions the problems with volatile:

请注意,应用 volatile 不会阻止写入后跟从被交换中读取,这会造成脑筋急转弯.乔·达菲下面的例子很好地说明了这个问题:如果 Test1 和Test2 同时运行在不同的线程上,a 和b 最终都为 0(尽管使用了 volatilex 和 y)

Notice that applying volatile doesn’t prevent a write followed by a read from being swapped, and this can create brainteasers. Joe Duffy illustrates the problem well with the following example: if Test1 and Test2 run simultaneously on different threads, it’s possible for a and b to both end up with a value of 0 (despite the use of volatile on both x and y)

接着是 MSDN 文档不正确的注释:

Followed by a note that the MSDN documentation is incorrect:

MSDN 文档指出使用 volatile 关键字可确保确保该字段中始终存在最新值.这是不正确的,因为正如我们所见,先写后读可以重新排序.

The MSDN documentation states that use of the volatile keyword ensures that the most up-to-date value is present in the field at all times. This is incorrect, since as we’ve seen, a write followed by a read can be reordered.

我检查了 MSDN 文档,这是最后一次更改在 2015 年但仍然列出:

I've checked the MSDN documentation, which was last changed in 2015 but still lists:

volatile 关键字表示一个字段可能被修改多个线程同时执行.字段是声明的 volatile 不受编译器优化的影响假设由单个线程访问.这确保了最字段中始终存在最新值.

The volatile keyword indicates that a field might be modified by multiple threads that are executing at the same time. Fields that are declared volatile are not subject to compiler optimizations that assume access by a single thread. This ensures that the most up-to-date value is present in the field at all times.

现在我仍然避免使用 volatile 支持更详细的以防止线程使用陈旧数据:

Right now I still avoid volatile in favor of the more verbose to prevent threads using stale data:

private int foo;
private object fooLock = new object();
public int Foo {
    get { lock(fooLock) return foo; }
    set { lock(fooLock) foo = value; }
}

关于多线程的部分是在 2011 年写的,这个论点今天仍然有效吗?是否应该不惜一切代价避免使用 volatile 以支持锁定或完整内存栅栏,以防止引入非常难以产生的错误,如上所述甚至依赖于它运行的 CPU 供应商?

As the parts about multithreading were written in 2011, is the argument still valid today? Should volatile still be avoided at all costs in favor of locks or full memory fences to prevent introducing very hard to produce bugs that as mentioned are even dependent on the CPU vendor it's running on?

推荐答案

Volatile 在其当前实现中没有被破坏,尽管流行的博客文章声称这样.然而,它的指定很糟糕,并且在字段上使用修饰符来指定内存排序的想法并不是那么好(将 Java/C# 中的 volatile 与 C++ 的原子规范进行比较,后者有足够的时间从早期的错误中吸取教训).另一方面,MSDN 文章显然是由一个没有业务谈论并发并且完全是假的人写的.唯一明智的选择是完全忽略它.

Volatile in its current implementation is not broken despite popular blog posts claiming such a thing. It is however badly specified and the idea of using a modifier on a field to specify memory ordering is not that great (compare volatile in Java/C# to C++'s atomic specification that had enough time to learn from the earlier mistakes). The MSDN article on the other hand was clearly written by someone who has no business talking about concurrency and is completely bogus.. the only sane option is to completely ignore it.

Volatile 保证在访问字段时获取/释放语义,并且只能应用于允许原子读写的类型.不多也不少.这足以有效地实现许多无锁算法,例如 非阻塞哈希图.

Volatile guarantees acquire/release semantics when accessing the field and can only be applied to types that allow atomic reads and writes. Not more, not less. This is enough to be useful to implement many lock-free algorithms efficiently such as non-blocking hashmaps.

一个非常简单的示例是使用易失性变量来发布数据.由于 x 上的 volatile,以下代码段中的断言无法触发:

One very simple sample is using a volatile variable to publish data. Thanks to the volatile on x, the assertion in the following snippet cannot fire:

private int a;
private volatile bool x;

public void Publish()
{
    a = 1;
    x = true;
}

public void Read()
{
    if (x)
    {
        // if we observe x == true, we will always see the preceding write to a
        Debug.Assert(a == 1); 
    }
}

Volatile 并不容易使用,在大多数情况下,您最好采用一些更高级别的概念,但是当性能很重要或您正在实施一些低级数据结构时,volatile 可能会非常有用.

Volatile is not easy to use and in most situations you are much better off to go with some higher level concept, but when performance is important or you're implementing some low level data structures, volatile can be exceedingly useful.

这篇关于'volatile' 关键字在 C# 中仍然无效吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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