2009-12-10 70 views
2

我想使用生产者消费者模式来处理和保存一些数据。我使用的AutoResetEvent这里两个therads之间的信令是代码我有生产者消费者与AutoResetEvent

这里是生产函数

public Results[] Evaluate() 
    { 
     processingComplete = false; 
     resultQueue.Clear(); 
     for (int i = 0; i < data.Length; ++i) 
      { 
       if (saveThread.ThreadState == ThreadState.Unstarted) 
        saveThread.Start(); 
       //-.... 
       //Process data 
       // 
       lock (lockobject) 
       { 
        resultQueue.Enqueue(result); 
       } 

       signal.Set(); 
      } 
      processingComplete = true; 
     } 

,这里是消费函数

private void SaveResults() 
    { 
     Model dataAccess = new Model(); 

     while (!processingComplete || resultQueue.Count > 0) 
     { 
      if (resultQueue.Count == 0) 
       signal.WaitOne(); 
      ModelResults result; 
      lock (lockobject) 

      { 
       result = resultQueue.Dequeue(); 
      } 
      dataAccess.Save(result); 
     } 
     SaveCompleteSignal.Set(); 
    } 

所以我的问题是有时候resultQueue.Dequeue()会抛出InvalidOperation异常,因为Queue是空的。我不知道我做错了什么不应该signal.WaitOne()上面那个块队列是空的?

回答

2

由于缺乏适当的锁定,您有同步问题。

您应锁定所有队列访问权限,包括计数检查。

此外,以这种方式使用Thread.ThreadState是个“坏主意”。来自MSDN的ThreadState文档:

“线程状态只在调试场景中感兴趣,您的代码永远不应该使用线程状态来同步线程的活动。

你不能依靠这个作为处理同步的手段。您应该重新设计,以确保线程在使用之前启动。如果它没有启动,只是不要初始化它。 (你总是可以使用空检查 - 如果线程为null,则创建它并启动它)。

0

你必须把锁()周围所有引用队列。您在识别处理完成时也会遇到一些问题(在队列的末尾您会收到信号,但队列将为空)。

public Results[] Evaluate() 
{ 
    processingComplete = false; 
    lock(lockobject) 
    { 
     resultQueue.Clear(); 
    } 
    for (int i = 0; i < data.Length; ++i) 
    { 
     if (saveThread.ThreadState == ThreadState.Unstarted) 
      saveThread.Start(); 
     //-.... 
     //Process data 
     // 
     lock (lockobject) 
     { 
      resultQueue.Enqueue(result); 
     } 

     signal.Set(); 
    } 
    processingComplete = true; 
} 

private void SaveResults() 
{ 
    Model dataAccess = new Model(); 

    while (true) 
    { 
     int count; 

     lock(lockobject) 
     { 
      count = resultQueue.Count; 
     } 
     if (count == 0) 
      signal.WaitOne(); 

     lock(lockobject) 
     { 
      count = resultQueue.Count; 
     } 
     // we got a signal, but queue is empty, processing is complete 
     if (count == 0) 
      break; 

     ModelResults result; 
     lock (lockobject) 
     { 
      result = resultQueue.Dequeue(); 
     } 
     dataAccess.Save(result); 
    } 
    SaveCompleteSignal.Set(); 
}