线程同步打印字符串

Thread synchronization printing strings

我写了一个小程序打印 "x",然后是“+”,然后又是 "x" 等等。 想法是在两个线程中使其成为 运行,以便第一个线程打印 "x",第二个线程打印“+”。输出如下所示: "x" -> 线程号 1 "+" -> 线程号 2 "x" -> 线程号 1enter code here "+" -> 线程号 2 等等..

我写的似乎工作正常但在我看来它是用 很老套的方式:

 public class Example
 {
    private static int count = 10;
    private static int i = 0;
    private static bool isOneActive = false;


  private static void Run1(object o)
  {
      string s = o as string;

      while(true)
      {
          if (!isOneActive)
          {
              Console.WriteLine("Hello from thread number: " +   
                      Thread.CurrentThread.ManagedThreadId + " -> " + s);
              isOneActive = true;
              if (i++ > count) break;
          }
      }
  }

  private static void Run2(object o)
  {
      string s = o as string;

      while(true)
      {
          if (isOneActive)
          {
              Console.WriteLine("Hello from thread number: " + 
                Thread.CurrentThread.ManagedThreadId + " -> " + s);
              isOneActive = false;
              if (i++ > count) break;
          }
      }
  }

  static void Main()
  {
      Thread t1 = new Thread(Run1);
      Thread t2 = new Thread(Run2);
      t1.Start("x");
      t2.Start("+");
  }

我知道现在 .NET 有很多用于线程同步的工具,例如 ManualResetEvent class 和任务库。那么我们如何使用 ManualResetEvent class 编写相同的程序呢?有可能吗?

您的代码不仅过时,而且效率很低。它无缘无故地旋转,除了等待什么都不做;这叫做 Busy wait 应尽可能避免。

更好的方法是使用评论中提到的 Waithandles。

对代码进行很少更改的简单实现将如下所示。

public class Example
{
    private static int count = 10;
    private static int i = 0;
    private static AutoResetEvent firstEvent = new AutoResetEvent(true);
    private static AutoResetEvent secondEvent = new AutoResetEvent(false);


    private static void Run1(object o)
    {
        string s = o as string;

        while (true)
        {
            firstEvent.WaitOne();
            Console.WriteLine("Hello from thread number: " + Thread.CurrentThread.ManagedThreadId + " -> " + s);
            secondEvent.Set();
            if (Interlocked.Increment(ref i) > count)
                break;
        }
    }

    private static void Run2(object o)
    {
        string s = o as string;

        while (true)
        {
            secondEvent.WaitOne();
            Console.WriteLine("Hello from thread number: " + Thread.CurrentThread.ManagedThreadId + " -> " + s);
            firstEvent.Set();
            if (Interlocked.Increment(ref i) > count)
                break;
        }
    }

    static void Main()
    {
        Thread t1 = new Thread(Run1);
        Thread t2 = new Thread(Run2);
        t1.Start("x");
        t2.Start("+");
    }
}

请注意,firstEvent 是通过将 initialState 标志设置为 true 来实例化的,这意味着第一个线程最初不会等待。

考虑这个例子 (fiddle):

    static void Main(string[] args)
    {
        var console = new object();
        int i = 0;
        Task.Run(() =>
        {
            lock (console)
                while (i++ < 10)
                {
                    Console.Write(i);
                    Monitor.Pulse(console);
                    Monitor.Wait(console);
                }
        });
        Task.Run(() =>
        {
            lock (console)
                while (i < 10)
                {
                    Console.Write('+');
                    Monitor.Pulse(console);
                    Monitor.Wait(console);
                }
        });
        Console.ReadLine(); // Task.WaitAll might be better, remove for fiddle
    }