证明代码示例失败,没有volatile

时间:2014-07-03 14:10:59

标签: c# multithreading concurrency volatile

下面是一个C#代码示例,它是破坏的Java代码的逐字翻译(至少在Mac OS X上已被证明会破坏(即第二个线程可能无法观察到sharedValue值的更改) 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

2 个答案:

答案 0 :(得分:3)

尝试运行以下程序的RELEASE构建(不要从调试器运行它,否则演示不会起作用 - 所以通过&#34; Debug | Start而不调试&#34;)运行发布构建:

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

答案 1 :(得分:2)

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

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");
  }

}