我们正在使用.NET 4.5.1开发应用程序,并在后台使用SemaphoreSlim
实现了我自己的“异步锁”。要锁定,我们使用以下方法:
public async Task<IDisposable> LockAsync(CancellationToken cancellationToken = default(CancellationToken))
{
await SyncRoot.WaitAsync(cancellationToken).ConfigureAwait(false);
return this;
}
其中
SyncRoot
是new SemaphoreSlim(1)
实例。这似乎在“生产中”工作正常,但是通过以下单元测试失败:
for (int i = 0; i < numberOfTasks; i++)
{
tasks[i] = Task.Run<Task>(async () =>
{
Interlocked.Increment(ref counterAtomicBegin);
using (await alock.LockAsync().ConfigureAwait(false))
{
counterLocked += 1;
}
Interlocked.Increment(ref counterAtomicEnd);
});
}
最后的
counterLocked
和counterAtomicBegin
不相等(在10万个任务中,它们〜1k关闭)。我是在做错什么还是这是
SemaphoreSlim
的问题?更新:建议删除嵌套的逻辑并改编文本。
请参见以下代码(可以在LINQPad中执行)进行测试:http://pastebin.com/WXecZxqu
最佳答案
您的逻辑不正确。
异步锁不是线程仿射的,因此持有锁的线程的整个概念是不正确的。而是,代码的特定部分持有该锁,并且该代码的某些部分可以在不同的线程上执行。
我认为recursive locks are a bad idea(链接是指向我的博客文章的详细信息)。从理论上讲,可以编写一个递归异步锁(我知道的唯一实现是part of the test suite for my AsyncEx library),但是它只能在.NET 4.5完整框架上运行,我仍然认为这是一个坏主意。
关于c# - SemaphoreSlim无法在极端条件下工作?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/22482042/