12

重要なセクションを保護するために、ロックまたは同様の同期を使用したいと考えています。同時に、CancellationToken をリッスンしたいと考えています。

現在、このようなミューテックスを使用していますが、ミューテックスのパフォーマンスはそれほど高くありません。ミューテックスの代わりに、他の同期クラス (新しい .Net 4.0 を含む) を使用できますか?

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

2 に答える 2

17

.NET 4.0 Framework機能SemaphoreSlim Classを見てください。SemaphoreSlim.Wait(CancellationToken)メソッドを提供します。

CancellationToken を観察しながら、SemaphoreSlim に入ることができるまで現在のスレッドをブロックします。

このような単純なケースでセマフォを使用すると、当初は複数のスレッドへのアクセスを提供するように設計されていたため、オーバーヘッドになる可能性がありますが、おそらく便利だと思うかもしれません。

編集: コード スニペット

CancellationToken token = new CancellationToken();            
SemaphoreSlim semaphore = new SemaphoreSlim(1,1);
bool tokenCanceled = false;

try {
   try {
      // block section entrance for other threads
      semaphore.Wait(token);
   }
   catch (OperationCanceledException) {
      // The token was canceled and the semaphore was NOT entered...
      tokenCanceled = true;
   }
   // critical section code
   // ...
   if (token.IsCancellationRequested)
   {
       // ...
   }
}
finally { 
   if (!tokenCanceled)
      semaphore.Release();
}
于 2011-09-14T13:28:33.487 に答える
2
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
}

ここで協同組合のキャンセルをカバーするいくつかの良いもの

于 2011-09-14T13:40:32.940 に答える