【问题标题】:Thread synchronization printing strings线程同步打印字符串
【发布时间】:2015-02-16 13:33:51
【问题描述】:

我写了一个小程序,它打印“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 类和任务库。那么我们如何使用 ManualResetEvent 类编写相同的程序呢?有可能吗?

【问题讨论】:

  • 部分题外话,但是当您写入完全相同的控制台时,为什么需要使用线程?
  • @Sayse 嗨,这是一个面试问题,他们说我用很老的方式写的
  • 您可以使用lock(或Monitor.TryEnter,取决于要求)进行同步。你必须阅读more
  • lockMonitor.PulseMonitor.Wait 一起使用,但实际上 Waithandle 在这里更好。
  • 关于 Sayse 的评论:让两个线程一个接一个地运行是一个奇怪的要求。为什么在这种情况下甚至有两个线程?至于您的解决方案,我认为真正的问题是效率低下的忙等待。

标签: c# multithreading synchronization


【解决方案1】:

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

更好的方法是使用 cmets 中所述的 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 的情况下实例化的,这意味着第一个线程最初不会等待。

【讨论】:

  • 是的,这很棒,正是我想要的。但是有一件事我仍然没有得到 - firstEvent 被实例化为 true 但在 Run1 WaitOne 被调用。它不会阻塞线程1吗?
  • @user3603343 不,当信号为Set 时(我们通过将true 传递给构造函数)调用WaitOne 不会阻塞。我建议阅读 thisthis 以更好地理解线程概念。
【解决方案2】:

考虑这个例子 (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
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-10
    • 1970-01-01
    • 2019-11-05
    相关资源
    最近更新 更多