2009-12-10 5 views
2

일부 데이터를 처리하고 저장하기 위해 생산자 소비자 패턴을 사용하려고합니다. 내가 여기에 두 therads 사이에 신호를위한 AutoResetEvent를 사용하고 여기생산자 소비자 AutoResetEvent를 사용하여

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(); 
    } 

그래서 내 문제는 소비자 함수 내가 여기

이 생산자 기능

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; 
     } 

코드입니다 그리고 때로는 resultQueue.Dequeue()가 Queue가 비어있어 InvalidOperation 예외를 throw합니다. 내가 잘못하고있는 것이 확실하지 않다. 그 블록 위의 신호. 대기열()은 대기열이 비어 있지 않은가?

답변

1

동기화 된 컨텍스트 외부에서 큐 수를 확인하십시오. 대기열은 스레드 세이프가 아니기 때문에 문제가 될 수 있습니다 (Enqueue가 프로세스의 Count 반환 값 1이지만 대기열에서 항목을 제거 할 수없는 경우도 있음). 둘 이상의 소비자를 사용하는 경우 심각한 오류가 발생할 수 있습니다.

Joseph Albahari가 작성한 스레딩 기사를 읽으려면 good sample for your problema "better" solution without OS synchronization objects도 있어야합니다.

2

잠금이 제대로되어 있지 않아 동기화 문제가 있습니다.

카운트 검사를 포함하여 모든 대기열 액세스를 잠 가야합니다.

또한이 방법으로 Thread.ThreadState을 사용하는 것은 "나쁜 생각"입니다. ThreadState에 대한 MSDN 문서에서 :

"스레드 상태는 디버깅 시나리오에서만 중요하며 코드는 스레드 상태를 동기화하는 데 스레드 상태를 사용하면 안됩니다."

동기화를 처리하는 방법으로는 신뢰할 수 없습니다. 쓰레드가 사용되기 전에 시작되도록 재 설계해야합니다. 시작되지 않은 경우 초기화하지 마십시오. null 체크를 사용할 수 있습니다. thread가 null의 경우, 그것을 작성해 개시합니다.

0

모두 대기열에 대한 lock()을 넣어야합니다. 또한 처리 완료 확인과 관련하여 몇 가지 문제가 있습니다 (대기열의 끝에서 신호를 받지만 대기열은 비어있게됩니다).

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(); 
} 
관련 문제