【发布时间】:2021-08-16 07:59:45
【问题描述】:
我不得不使用 SemaphoreSlim 来确保对我的代码的某些部分进行单线程访问,并且想确保我正确地处理了所有内容。假设我有以下课程:
public class Foo
{
private readonly CancellationTokenSource _canceller = new CancellationTokenSource();
private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1);
~Foo()
{
Dispose(false);
GC.SuppressFinalize(this);
}
public void Dispose()
{
Dispose(true);
}
protected void Dispose(bool disposing)
{
if (_disposed)
return;
_canceller.Cancel();
if (_disposing)
_semaphore.Dispose();
_disposed = true;
}
public async Task ExecuteAsync()
{
try
{
await _semaphore.WaitAsync(_canceller.Token);
}
catch (OperationCanceledException)
{
throw new ObjectDisposedException(nameof(Foo), "Cannot execute on a Foo after it has been disposed");
}
try
{
// Critical section
}
finally
{
_semaphore.Release();
}
}
}
当我调用Dispose(true) 时,我实际上是一个接一个地执行以下几行:
_canceller.Cancel();
_semaphore.Dispose();
我的问题是,当前等待关键部分的任何其他线程/任务会发生什么?我能保证他们总是首先看到 cancellation,因此信号量被处理不会有问题吗?到目前为止,这还没有造成任何问题,但这并不意味着它是安全的。
【问题讨论】:
-
旁注:从终结器调用
TaskCompletionSource.Cancel是不安全的。 I recommend not having a finalizer at all.