certificate代码示例失败,没有volatile

下面是一个C#代码示例,它是一个破坏的Java代码的逐字翻译(已certificate破坏(即第二个线程可能无法观察到sharedValue值的变化)至少在Mac OS X 10.9,Java 1.8(64位)上),Arrandale(1插槽x 2核x 2 HT = 4个HW线程)):

 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

尝试运行以下程序的RELEASE构建(不要从调试器运行它,否则演示将无法运行 – 因此通过“Debug | Start without debugging”运行发布版本):

 using System; using System.Threading; using System.Threading.Tasks; namespace Demo { internal class Program { private void run() { Task.Factory.StartNew(resetFlagAfter1s); int x = 0; while (flag) ++x; Console.WriteLine("Done"); } private void resetFlagAfter1s() { Thread.Sleep(1000); flag = false; } private volatile bool flag = true; private static void Main() { new Program().run(); } } } 

程序将在一秒钟后终止。

现在从线上删除volatile

 private volatile bool flag = true; // <--- Remove volatile from this 

完成后,程序现在永远不会终止。 (在Windows 8 x64,.Net 4.5上测试)

但请注意,在某些情况下,使用Thread.MemoryBarrier()而不是声明变量volatile更合适,即:

 while (flag) { Thread.MemoryBarrier(); ++x; } 

有关更多信息,请参阅http://blogs.msdn.com/b/brada/archive/2004/05/12/130935.aspx

这应该陷入无限循环(我现在无法测试)

 public class Test { private bool loop = true; public static void Main() { Test test = new Test(); Thread thread = new Thread(DoStuff); thread.Start(test); Thread.Sleep(1000); test.loop = false; Console.WriteLine("loop is now false"); } private static void DoStuff(object o) { Test test = (Test)o; Console.WriteLine("Entering loop"); while (test.loop) { } Console.WriteLine("Exited loop"); } 

}