8

我想使用鎖定或類似的同步來保護關鍵部分。同時我想收聽CancellationToken。c#鎖定並收聽CancellationToken

現在我正在使用這樣的互斥量,但互斥量沒有那麼好的性能。我可以使用任何其他同步類(包括新的.Net 4.0)而不是互斥量嗎?

WaitHandle.WaitAny(new[] { CancelToken.WaitHandle, _mutex}); 
CancelToken.ThrowIfCancellationRequested(); 
+0

你可以張貼一些代碼顯示了關鍵部分,你目前如何釋放互斥? –

回答

11

.NET 4.0 Framework新功能SemaphoreSlim Class看看。它提供了SemaphoreSlim.Wait(CancellationToken)方法。

阻止當前線程,直到它可以進入SemaphoreSlim,而 觀察的CancellationToken

從在這種簡單的情況下,使用旗語某些角度來看,因爲它最初的目的是提供可能是一個開銷一個多線程訪問,但也許你可能會覺得它很有用。

編輯:代碼片段

CancellationToken token = new CancellationToken();    
SemaphoreSlim semaphore = new SemaphoreSlim(1,1); 

try { 
    // block section entrance for other threads 
    semaphore.Wait(token); 

    // critical section code 
    // ... 
    if (token.IsCancellationRequested) 
    { 
     // ... 
    } 
} 
finally { 
    semaphore.Release(); 
} 
+0

請放一些try-finally around :-) – xanatos

+0

@xanatos:你是說有什麼異常?這是僞代碼來演示SemaphoreSlim如何與CancellationToken綁定,而不再是:) – sll

+0

@xanatos ...爲什麼不自己這樣做? – Carsten

-2

可以使用Monitor對象來獲得性能上的位因爲它也表示在MSDN:

雖然互斥可用於幀內處理線程同步,使用監視器通常是優選的,因爲顯示器是爲.NET Framework專門設計的,因此更好地利用資源

的更多信息

http://msdn.microsoft.com/en-us/library/system.threading.monitor.aspx

CancellationToken爲您提供了異步或長時間運行的同步操作的協作取消模型。 如果您想要將它與監視器類一起使用,則必須構造代碼才能釋放鎖,前提是這是取消請求。你可以這樣做以下:

public void ThreadSafeMethod() 
     { 
      var cancellationToken=new CancellationToken(); 
      object locker=new object(); 
      Monitor.Enter(locker); 
      try 
      { 
       //your code 



       if (token.IsCancellationRequested) 
       { 
        Monitor.Exit(locker); 

       } 

      } 
      finally 
      { 
       Monitor.Exit(locker); 
      } 
     } 

,或者如果你想使用ThrowIfCancellationRequested:

public void ThreadSafeMethod() 
     { 
      var cancellationToken=new CancellationToken(); 
      object locker=new object(); 
      Monitor.Enter(locker); 
      try 
      { 
       //your code 

       cancellationToken.ThrowIfCancellationRequested(); 
      } 
      catch(OperationCanceledException) 
      { 

      } 
      finally 
      { 
       Monitor.Exit(locker); 
      } 
     } 
+0

好的,但那正是我想要做的。你能告訴我一個例子嗎? – Karsten

+0

可以將'Monitor'與'CancellationToken'結合嗎?我不知道... – xanatos

+0

答案已編輯 –

0
private object _lockObject = new object(); 

lock (_lockObject) 
{ 
    // critical section 
    using (token.Register(() => token.ThrowIfCancellationRequested()) 
    { 
     // Do something that might need cancelling. 
    } 
} 

令牌上調用Cancel()將導致ThrowIfCancellationRequested()因爲這是什麼掛接到Register回調被調用。你可以在這裏放置任何你想要的取消邏輯。這種方法非常棒,因爲您可以通過強制導致呼叫完成的條件來取消阻塞呼叫。

ThrowIfCancellationRequested拋出OperationCanceledException。您需要在調用線程上處理此問題,否則您的整個過程可能會被取消。這樣做的一個簡單方法是使用Task類開始您的任務,該類將聚合所有例外,供您在調用線程上處理。

try 
{ 
    var t = new Task(() => LongRunningMethod()); 
    t.Start(); 
    t.Wait(); 
} 
catch (AggregateException ex) 
{ 
    ex.Handle(x => true); // this effectively swallows any exceptions 
} 

一些好東西here覆蓋合作社消除

+1

在調用線程時拋出異常Cancel – Karsten

+0

如果您的意思是OperationCanceledException,那麼這是由設計決定的 - 這就是ThrowIfCancellationRequested方法拋出的。您應該使用建議的模式(更新的答案)在呼叫方處理它。 –

+0

關於你的語句「調用'Cancel()'在CancellationTokenSource上將導致'ThrowIfCancellationRequested()'被調用」...這個行爲可以通過使用[Cancel(bool)](https:// msdn .microsoft.com/en-us/library/dd321703(v = vs.110).aspx)過載。 –