以下C#代码线程是否安全?

Fua*_*kov 6 c# multithreading thread-safety

我正在尝试学习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"); }
  }
}
Run Code Online (Sandbox Code Playgroud)

在Java中,除非将"完成"定义为volatile,否则代码将不安全.C#内存模型如何处理这个问题?

伙计们,谢谢大家的答案.非常感激.

Jon*_*eet 7

嗯,有明显的竞争条件,他们都可以done看作是假的并执行if身体 - 无论记忆模型如何都是如此.使donevolatile变得无法修复,也无法在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);
    }
}
Run Code Online (Sandbox Code Playgroud)

虽然在我当前的笔记本电脑上这已经终止,我已经使用了其他几乎完全相同的代码将永远运行的机器 - 它永远不会"看到" stop第二个线程中的更改.

基本上,我试图避免编写无锁代码,除非它使用由真正了解其内容的人提供的更高级别的抽象 - 比如.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");
     }
  }
}
Run Code Online (Sandbox Code Playgroud)

这里,值的变化及其测试作为一个单元执行:CompareExchange如果当前为0,则仅将值设置为1,并返回值.因此,只有一个线程会看到返回值为0.

另外要记住的一点是:你的问题很模糊,因为你还没有定义"线程安全"的含义.我已经猜到了你的意图,但你从来没有说清楚.阅读Eric Lippert撰写的这篇博客文章 - 非常值得.


Tej*_*ejs 5

不,这不是线程安全的.您可能有一个线程检查condition(if(!done)),另一个线程检查相同的条件,然后第一个线程执行代码块(done = true)中的第一行.

您可以通过锁使其线程安全:

lock(this)
{
    if(!done)
    {
        done = true;
        Console.WriteLine("Done");
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 虽然使用锁是一个很好的主意,但"锁定这个"是一个糟糕的编程习惯.有关详细信息,请参见http://stackoverflow.com/questions/5926393/how-to-ensure-thread-safe-in-the-static-method/5940285#5940285. (2认同)