2012-11-04 70 views
2

我寫了一個DirectSoundWrapper,但我只能通過MTA線程訪問接口。 所以我創建了一個在後臺工作的線程並在隊列中執行動作。 我做了這樣的事情:C#線程同步監視器+ ResetEvent

private void MTAQueue() 
{ 
    lock (queueLockObj) 
    { 
     do 
     { 
      if (marshalThreadItems.Count > 0) 
      { 
       MarshalThreadItem item; 
       item = marshalThreadItems.Dequeue(); 
       item.Action(); 
      } 
      else 
      { 
       Monitor.Wait(queueLockObj); 
      } 
     } while (!disposing); 
    } 
} 

我執行相應的操作是這樣的:

private void ExecuteMTAAction(Action action) 
{ 
    if (IsMTAThread) 
     action(); 
    else 
    { 
     lock (queueLockObj) 
     { 
      MarshalThreadItem item = new MarshalThreadItem(); 
      item.Action = action; 
      marshalThreadItems.Enqueue(item); 

      Monitor.Pulse(queueLockObj); 
     } 
    } 
} 

但現在我想等待完成動作被調用。所以,我想用一個ManuelResetEvent:

private void ExecuteMTAAction(Action action) 
{ 
    if (IsMTAThread) 
     action(); 
    else 
    { 
     lock (queueLockObj) 
     { 
      MarshalThreadItem item = new MarshalThreadItem(); 
      item.Action = action; 
      item.waitHandle = new ManualResetEvent(false); //setup 
      marshalThreadItems.Enqueue(item); 

      Monitor.Pulse(queueLockObj); //here the pulse does not pulse my backgrond thread anymore 
      item.waitHandle.WaitOne(); //waiting 
     } 
    } 
} 

我的後臺線程我只是編輯是這樣的:

item.Action(); 
item.waitHandle.Set(); 

的問題是,後臺線程沒有得到了脈衝,只是一直等待(監視器.wait(queueLockObj))和我的主線程調用動作等待manuelresetevent ...?

爲什麼?

回答

0

問題在你的代碼是以前Monitor.Wait(queueLockObj)將退出和線程可以處理項目另一個線程(ExecuteMTAAction方法)必須調用Monitor.Exit(queueLockObj),但打電話item.waitHandle.WaitOne()阻止這一呼籲 - 你有死鎖。因此 - 您必須在item.waitHandle.WaitOne()之前致電Monitor.Exit(queueLockObj)。 此代碼將正常工作:

private void ExecuteMTAAction(Action action) 
{ 
    if (IsMTAThread) 
     action(); 
    else 
    { 
     lock (queueLockObj) 
     { 
      MarshalThreadItem item = new MarshalThreadItem(); 
      item.Action = action; 
      item.waitHandle = new ManualResetEvent(false); //setup 
      marshalThreadItems.Enqueue(item); 

      Monitor.Pulse(queueLockObj); 
     } 
      item.waitHandle.WaitOne(); //waiting   
    } 
}