我必须使用 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();
我的问题是,当前正在等待关键部分的任何其他线程/任务会发生什么?我能保证他们永远都能看到消除首先,信号量的处理不会有问题吗?到目前为止,这还没有造成任何问题,但这并不意味着它是安全的。
The SemaphoreSlim 的文档 https://learn.microsoft.com/en-us/dotnet/api/system.threading.semaphoreslim?view=net-5.0看起来你的问题非常具体。
SemaphoreSlim 的所有公共和受保护成员都是线程安全的,可以在多个线程中同时使用,但 Dispose() 除外,Dispose() 必须仅在 SemaphoreSlim 上的所有其他操作完成后才能使用。
保证这一点的唯一真正方法所有其他操作均已完成是为了确保所有任务都已完成,如文档中的示例所示。
public class Foo
{
private readonly List<Task> _semaphoreTasks = new list<Task>();
protected void Dispose(bool disposing)
{
if (_disposed)
return;
_canceller.Cancel();
if (_disposing)
{
Task.WaitAll(tasks);
_semaphore.Dispose();
}
_disposed = true;
}
public async Task ExecuteAsync()
{
try
{
var task = _semaphore.WaitAsync(_canceller.Token);
_semaphoreTasks.Add(task);
await task;
// ...
这也很可能需要确保在执行处置时将事物添加到列表中。 (您可以将私有类变量设置为本地方法变量,然后将类变量设置为 null)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)