我想使用锁或类似的同步来保护关键部分。同时我想听一个CancellationToken。
现在我正在使用这样的互斥锁,但是互斥锁并没有那么好的性能。我可以使用任何其他同步类(包括新的.Net 4.0)而不是互斥锁吗?
WaitHandle.WaitAny(new[] { CancelToken.WaitHandle, _mutex});
CancelToken.ThrowIfCancellationRequested();
答案 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);
}
}