我们正在使用.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)实例。

这似乎在“生产中”工作正常,但是通过以下单元测试失败:

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不相等(在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/

10-11 07:27