【发布时间】:2014-07-03 14:10:58
【问题描述】:
下面是一个 C# 代码示例,它是至少在 Mac OS X 10.9 上对损坏的 Java 代码(已被证明是损坏的(即第二个线程可能无法观察到 sharedValue 值的变化)的逐字翻译), Java 1.8(64 位),Arrandale(1 个套接字 x 2 个内核 x 2 HT = 4 个硬件线程)):
using System;
using System.Threading;
class ThreadTest {
/* volatile */ private int sharedValue;
private void RunAsync() {
while (this.sharedValue == 0);
}
private bool Test() {
Thread t = new Thread(this.RunAsync);
t.IsBackground = true;
t.Start();
Thread.Sleep(10);
// Yes I'm aware the operation is not atomic
this.sharedValue++;
t.Join(10);
bool success = !t.IsAlive;
if (!success) {
Console.Write('.');
}
return success;
}
static void Main() {
long failureCount = 0L;
const long testCount = 10000L;
for (long i = 0; i < testCount; i++) {
if (!new ThreadTest().Test()) {
failureCount++;
}
}
Console.WriteLine();
Console.WriteLine("Failure rate: " + 100.0 * failureCount / testCount + "%");
}
}
令人惊讶的是,无论我在 .NET 4.0/Windows XP(32 位)上运行上述 C# 代码多少次,我都没有观察到一次失败。在 Mono(64 位)、Mac OS X 上运行时也没有任何故障。在这两种情况下,我只看到一个 CPU 内核处于忙碌状态。
您能否推荐一个 C# 代码示例,该示例错误地使用了共享变量并失败,除非该变量被标记为 volatile?
【问题讨论】:
-
Eric Lippert 对此有一些信息。他和 Joe Duffy 似乎暗示 x86 中的 CLR 上没有这种情况。 blog.coverity.com/2014/03/26/reordering-optimizations 和 joeduffyblog.com/2010/12/04/sayonara-volatile
-
感谢@MobyDisk 的链接。尽管如此,我已经在 Smithfield(1 插槽 x 1 核 x 2 HT)和 Arrandale(1 插槽 x 2 核 x 2 HT)的 .NET 4.0/Windows XP(32 位)上发现了上述代码,在分别在裸机和虚拟机中。关键是按照下面 Matthew Watson 的建议运行 release 构建。
标签: c# multithreading concurrency volatile