SemaphoreSlim在极端条件下无法工作?

时间:2014-03-18 14:15:35

标签: c# .net asynchronous locking semaphore

我们正在使用.NET 4.5.1开发一个应用程序并实现了我自己的"异步锁定"在后台使用SemaphoreSlim。要锁定我们使用以下方法:

public async Task<IDisposable> LockAsync(CancellationToken cancellationToken = default(CancellationToken))
{
    await SyncRoot.WaitAsync(cancellationToken).ConfigureAwait(false);
    return this;
}

SyncRootnew 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);
    });
}

最后counterLockedcounterAtomicBegin不相等(在100k任务时它们的关闭时间约为1k)。

我做错了什么或这是SemaphoreSlim的问题?

更新:根据建议删除嵌套逻辑并调整文本 请参阅以下代码(可在LINQPad中执行)以测试它:http://pastebin.com/WXecZxqu

1 个答案:

答案 0 :(得分:1)

你的逻辑错误。

异步锁不是线程仿射的,因此持有锁的线程的整个概念是不正确的。相反,代码的某个部分持有锁,并且该代码的一部分可以在不同的线程上执行。

在我看来,recursive locks are a bad idea(链接到我的博文,详细介绍)。理论上可以编写一个递归异步锁(我知道的唯一实现是part of the test suite for my AsyncEx library),但它只适用于.NET 4.5完整框架,我仍然认为这是一个坏主意。