1

我正在阅读 MSDN文章,其中有一些使用Monitor类管理线程的示例。但偶尔在调试模式下在 VS2012 上运行示例并没有做任何事情。我假设线程在某种死锁中相互阻塞。有人可以解释一下,是什么导致了这种行为?

将代码复制到这篇文章:

 using System;
 using System.Threading;
 using System.Collections;

 namespace MonitorCS1
 {
    class MonitorSample
    {
        const int MAX_LOOP_TIME = 1000;
        Queue   m_smplQueue;

        public MonitorSample()
        {
            m_smplQueue = new Queue(); 
        }
        public void FirstThread()
        {
            int counter = 0;
            lock(m_smplQueue)
            {
                while(counter < MAX_LOOP_TIME)
                {
                    //Wait, if the queue is busy.
                    Monitor.Wait(m_smplQueue);
                    //Push one element.
                    m_smplQueue.Enqueue(counter);
                    //Release the waiting thread.
                    Monitor.Pulse(m_smplQueue); 

                    counter++;
                }
            }
        }
        public void SecondThread()
        {
            lock(m_smplQueue)
            {
                //Release the waiting thread.
                Monitor.Pulse(m_smplQueue);
                //Wait in the loop, while the queue is busy.
                //Exit on the time-out when the first thread stops. 
                while(Monitor.Wait(m_smplQueue,1000))
                {
                    //Pop the first element.
                    int counter = (int)m_smplQueue.Dequeue();
                    //Print the first element.
                    Console.WriteLine(counter.ToString());
                    //Release the waiting thread.
                    Monitor.Pulse(m_smplQueue);
                }
            }
        }
        //Return the number of queue elements.
        public int GetQueueCount()
        {
            return m_smplQueue.Count;
        }

        static void Main(string[] args)
        {
            //Create the MonitorSample object.
            MonitorSample test = new MonitorSample();           
            //Create the first thread.
            Thread tFirst = new Thread(new ThreadStart(test.FirstThread));
            //Create the second thread.
            Thread tSecond = new Thread(new ThreadStart(test.SecondThread));
            //Start threads.
            tFirst.Start();
            tSecond.Start();
            //wait to the end of the two threads
            tFirst.Join();
            tSecond.Join();         
            //Print the number of queue elements.
            Console.WriteLine("Queue Count = " + test.GetQueueCount().ToString());
        }
    }
 }
4

1 回答 1

0

您在与锁中相同的对象上使用 Monitor.Wait。这是主要问题。值得一提的是 Lock 和 Monitor.Wait 在引擎盖下是相同的 - 所以你是双重锁定:)。Lock 只是编译器变成监视器的一个很好的关键字。

来自高事务背景,最好有一个私有的单例对象来锁定。这很好,因为它在内存中的引用不会改变 - 对于非静态类,它可能会改变。

还值得一提的是,让 2 个线程以正确的顺序开始,就像您在代码中所做的那样,可能不会导致它们以正确的顺序开始。

这是使用上述建议编写的代码示例(仅使用 lock 关键字):

class LockSample
  {
    const int MAX_LOOP_TIME = 50000;
    private static object queueLocker = new object();
    Queue m_smplQueue;

    public LockSample()
    {
      m_smplQueue = new Queue();
    }
    public void FirstThread()
    {
      Console.WriteLine("In thread 1");
      int counter = 0;
      lock (queueLocker)
      {
        Console.WriteLine("Adding to queue");
        while (counter < MAX_LOOP_TIME)
        { //Push one element.
          m_smplQueue.Enqueue(++counter);
        }
      }
    }

    public void SecondThread()
    {
      Console.WriteLine("In thread 2");
      lock (queueLocker)
      {
        Console.WriteLine("Removing items from the queue");
        while (m_smplQueue.Count > 0)
        {
          //Pop the first element.
          int counter = (int)m_smplQueue.Dequeue();
          //Print the first element.
          Console.Write("\r{0}", counter.ToString());
        }
      }
    }

    static void Main(string[] args)
    {
      //Create the MonitorSample object.
      LockSample test = new LockSample();
      //Create the first thread.
      Thread tFirst = new Thread(new ThreadStart(test.FirstThread));
      //Create the second thread.
      Thread tSecond = new Thread(new ThreadStart(test.SecondThread));
      //Start threads.
      tFirst.Start();
      Thread.Sleep(100);
      tSecond.Start();
      //wait to the end of the two threads

      Console.WriteLine("Waiting for the thread 1");
      tFirst.Join();
      Console.WriteLine("Waiting for the thread 2");
      tSecond.Join();

      Console.WriteLine("\r\nfinished!");
      Console.Read();
    }
  }
于 2013-09-25T08:39:48.827 回答