c#锁定并听取CancellationToken

时间:2011-09-14 13:05:32

标签: c# multithreading .net-4.0 task-parallel-library cancellation-token

我想使用锁或类似的同步来保护关键部分。同时我想听一个CancellationToken。

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

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

3 个答案:

答案 0 :(得分:12)

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

  

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

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

编辑:代码段

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

答案 1 :(得分: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
}

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

答案 2 :(得分:-2)

你可以使用Monitor对象来获得性能,因为它也在MSDN中说明:

虽然互斥锁可以用于进程内线程同步,但通常首选使用Monitor,因为监视器是专门为.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);
            }
        }