首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > .NET > C# >

,分析一个线程同步代码片段优劣

2011-12-14 
高手进,分析一个线程同步代码片段优劣代码实现的功能如下:一个生产者线程,一个消费者程,生产一个产品,消费

高手进,分析一个线程同步代码片段优劣
代码实现的功能如下:一个生产者线程,一个消费者程,生产一个产品,消费一个,再生产,再消费...
A版代码如下:
  static void ProduceOneA()
  {
  lock (locker)
  {
  while (true)
  {
  if (isHave)
  Monitor.Wait(locker);

  Thread.Sleep(1000);
  Console.WriteLine("生产一个");
  isHave = true;
  Monitor.Pulse(locker);
  }  
  }
  }

  static void ConsumeOneA()
  {
  lock (locker)
  {
  while (true)
  {
  if(!isHave)
  Monitor.Wait(locker);

  Thread.Sleep(500);
  Console.WriteLine("消费一个");
  isHave = false;
  Monitor.Pulse(locker);
  }
  }
  }

  static object locker = new object();
  volatile static bool isHave = false;

  static void Main(string[] args)
  {
  new Thread(ProduceOneA).Start();
  new Thread(ConsumeOneA).Start();
  }

是比较常见的lock{while(){}}结构,B版代码如下:
  static void ProduceOneB()
  {
  while (true)
  {
  lock (locker)
  {
  if (isHave)
  Monitor.Wait(locker);
  Thread.Sleep(1000);
  Console.WriteLine("生产一个");
  isHave = true;
  Monitor.Pulse(locker);
  }
  }
  }

  static void ConsumeOneB()
  {
  while (true)
  {
  lock (locker)
  {
  if (!isHave)
  Monitor.Wait(locker);
  Thread.Sleep(500);
  Console.WriteLine("消费一个");
  isHave = false;
  Monitor.Pulse(locker);
  }
  }
  }

注意这里变成了while(){lock{}},这两个版本的代码都能达到目的,但孰优孰劣,高手给分析下,个人感觉lock{}里的同步代码应该越短约好如B版代码,但B版的结构频繁调用lock{}又是一个问题...

[解决办法]

C# code
        void ProduceOneA()         {                 while (Interlocked.Read(ref bRun) == 1)                 {                     try                      {                                ProduceHandler.waitone();                                            Console.WriteLine("生产一个");                             ConsumeHandler.set();                       }                      finally                      {                          Thread.Sleep(1000);                      }                }        }         void ConsumeOneA()         {                 while (Interlocked.Read(ref bRun) == 1)                 {                       try                      {     ConsumeHandler.waitone();                            Console.WriteLine("消费一个");                             ProduceHandler.set();                       }                      finally                      {                          Thread.Sleep(1000);                      }                }             }         }         private ReaderWriterLock m_RWHandlers = new ReaderWriterLock();        long m_Run = 0;        AutoResetEvent m_ConsumeHandler = new AutoResetEvent(false);        AutoResetEvent m_ProduceHandler = new AutoResetEvent(true);        static void Main(string[] args)         {             Interlocked.Exchange(ref m_Run, 1);            new Thread(new threadstart(ProduceOneA)).Start();             new Thread(new threadstart(ConsumeOneA)).Start();         } 


[解决办法]
A版本是错的。示例代码中可没使用while(true)。
lock是保护其中的代码不会同时被不同线程调用。lock块中使用while(ture)???除了第1个调用的线程,其它调用这部分代码的线程会卡在lock的地方,这段代码无法实现真正的多线程同时和多线程消费。
你的ProduceOneA和ConsumeOneA都只有一个,lock事实上没有起没有任何作用,所以没报问题。

lock块中的代码确实越少越好,不过至少包住读数据、处理数据、写数据的整个过程。
另外lock放在循环体内,单个处理线程效率降低、多个线程同时处理同一功能的,总效率会提高。但是如果循环变量的同步处理得不好,也容易出现问题。

Monitor才是起协调ProduceOneA和ConsumeOneA的生产和消费的功能的对象。
isHave可以去掉。它的功能看上去与Monitor完全一梓,而这种用于自行控制线程同步的全局状态,会影响后续扩展代码应用的。
[解决办法]
我发现微软给的列子有问题
大家可以检测一下,把微软的例子考下来运行一下,如果运气比较好的话,就会发现运行两三次就会死锁一次。
我简单的分析了一下原因。如果SecondeThread先锁m_smplQueues,那么FirstThread就会陷入死锁的状态,因为只有等到SecondeThread执行Monitor.Wait(m_smplQueue, 1000),FirstThread才能执行,但是线程一永远收不到Monitor.Pulse(m_smplQueue);就会死锁在那里,因为SecondeThread等不到线程一调用 Monitor.Pulse(m_smplQueue);等待一秒钟后就推出了,所以FirstThread永远的只有等在哪里了。

大家不要太相信微软的例子,实践才是硬道理

热点排行