我正在尝试学习C#中的线程.今天我在
http://www.albahari.com/threading/播种以下代码:
class ThreadTest { bool done; static void Main() { ThreadTest tt = new ThreadTest(); // Create a common instance new Thread (tt.Go).Start(); tt.Go(); } // Note that Go is now an instance method void Go() { if (!done) { done = true; Console.WriteLine ("Done"); } } }
在Java中,除非将“完成”定义为volatile,否则代码将不安全. C#内存模型如何处理这个问题?
伙计们,谢谢大家的答案.非常感激.
解决方法
好吧,有明显的竞争条件,他们都可以看到做错和执行if身体 – 无论记忆模型如何都是如此.完成volatile并不会解决这个问题,也不会在Java中修复它.
但是,是的,在一个线程中进行的更改可能会发生,但在另一个线程中不可见.这取决于cpu架构等.作为我的意思的一个例子,考虑这个程序:
using System; using System.Threading; class Test { private bool stop = false; static void Main() { new Test().Start(); } void Start() { new Thread(ThreadJob).Start(); Thread.Sleep(500); stop = true; } void ThreadJob() { int x = 0; while (!stop) { x++; } Console.WriteLine("Counted to {0}",x); } }
虽然在我当前的笔记本电脑上这已经终止,我已经使用了其他机器,其中几乎完全相同的代码将永远运行 – 它永远不会“看到”更改停止在第二个线程中.
基本上,我试图避免编写无锁代码,除非它使用由真正了解其内容的人提供的更高级别的抽象 – 比如.NET 4中的Parallel Extensions.
有一种方法可以使用Interlocked使这段代码无锁,并且很容易纠正.例如:
class ThreadTest { int done; static void Main() { ThreadTest tt = new ThreadTest(); // Create a common instance new Thread (tt.Go).Start(); tt.Go(); } // Note that Go is now an instance method void Go() { if (Interlocked.CompareExchange(ref done,1,0) == 0) { Console.WriteLine("Done"); } } }
这里,值的更改和测试将作为一个单元执行:如果当前为0,则CompareExchange仅将值设置为1,并返回旧值.因此,只有一个线程会看到返回值为0.
另外要记住的一点是:你的问题很模糊,因为你还没有定义“线程安全”的含义.我已经猜到了你的意图,但你从来没有说清楚.阅读this blog post by Eric Lippert – 非常值得.