我们正在使用.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)
个实例。
这似乎工作得很好&#34;在生产&#34;,但它失败了以下单元测试:
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
不相等(在100k任务时它们的关闭时间约为1k)。
我做错了什么或这是SemaphoreSlim
的问题?
更新:根据建议删除嵌套逻辑并调整文本 请参阅以下代码(可在LINQPad中执行)以测试它:http://pastebin.com/WXecZxqu
答案 0 :(得分:1)
你的逻辑错误。
异步锁不是线程仿射的,因此持有锁的线程的整个概念是不正确的。相反,代码的某个部分持有锁,并且该代码的一部分可以在不同的线程上执行。
在我看来,recursive locks are a bad idea(链接到我的博文,详细介绍)。理论上可以编写一个递归异步锁(我知道的唯一实现是part of the test suite for my AsyncEx library),但它只适用于.NET 4.5完整框架,我仍然认为这是一个坏主意。