c#锁定并监听CancellationToken

本文关键字:CancellationToken 监听 锁定 | 更新日期: 2023-09-27 18:08:38

我想使用锁或类似的同步来保护临界区。同时我想听一个CancellationToken

现在我正在使用这样的互斥锁,但是互斥锁没有那么好的性能。我可以使用任何其他同步类(包括新的。net 4.0)来代替互斥锁吗?

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

c#锁定并监听CancellationToken

看看.NET 4.0 Framework的新功能SemaphoreSlim class。它提供了semaphoreslimm . wait (CancellationToken)方法。

阻塞当前线程,直到它可以进入SemaphoreSlim观察CancellationToken

从某种角度来看,在这种简单的情况下使用信号量可能是一种开销,因为它最初的设计目的是为多个线程提供访问,但也许您会发现它很有用。

编辑:代码片段

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

关于合作取消的一些好东西

您可以使用带timeout的Monitor.TryEnter来等待锁并定期检查是否取消。

private bool TryEnterSyncLock(object syncObject)
{
    while(!Monitor.TryEnter(syncObject, TimeSpan.FromMilliseconds(100)))
    {
        if (cts_.IsCancellationRequested)
            return false;
    }
    return true;
}

注意,我不建议在高争用的情况下这样做,因为这会影响性能。我将使用它作为防止死锁的安全机制,以防你不能使用SemaphoreSlim,因为它具有与Monitor.Enter不同的相同线程重入语义。

在返回true后,必须使用Monitor.Exit释放syncObject上的锁。

相关文章:
  • 没有找到相关文章