【发布时间】:2014-01-27 23:37:52
【问题描述】:
在我们的一堂课中,我们大量使用SemaphoreSlim.WaitAsync(CancellationToken) 并取消了它。
当对WaitAsync 的呼叫在呼叫SemaphoreSlim.Release() 后不久被取消时,我似乎遇到了问题(我的意思是在ThreadPool 有机会处理排队项目之前),它将信号量置于无法获取更多锁的状态。
由于在调用Release() 和Cancel() 之间是否执行ThreadPool 项的不确定性,以下示例并不总是说明问题,对于这些情况,我已明确表示忽略运行。
这是我试图证明问题的示例:
void Main()
{
for(var i = 0; i < 100000; ++i)
Task.Run(new Func<Task>(SemaphoreSlimWaitAsyncCancellationBug)).Wait();
}
private static async Task SemaphoreSlimWaitAsyncCancellationBug()
{
// Only allow one thread at a time
using (var semaphore = new SemaphoreSlim(1, 1))
{
// Block any waits
semaphore.Wait();
using(var cts1 = new CancellationTokenSource())
{
var wait2 = semaphore.WaitAsync(cts1.Token);
Debug.Assert(!wait2.IsCompleted, "Should be blocked by the existing wait");
// Release the existing wait
// After this point, wait2 may get completed or it may not (depending upon the execution of a ThreadPool item)
semaphore.Release();
// If wait2 was not completed, it should now be cancelled
cts1.Cancel();
if(wait2.Status == TaskStatus.RanToCompletion)
{
// Ignore this run; the lock was acquired before cancellation
return;
}
var wasCanceled = false;
try
{
await wait2.ConfigureAwait(false);
// Ignore this run; this should only be hit if the wait lock was acquired
return;
}
catch(OperationCanceledException)
{
wasCanceled = true;
}
Debug.Assert(wasCanceled, "Should have been canceled");
Debug.Assert(semaphore.CurrentCount > 0, "The first wait was released, and the second was canceled so why can no threads enter?");
}
}
}
还有here LINQPad 实现的链接。
运行之前的示例几次,有时您会看到取消WaitAsync 不再允许任何线程进入。
更新
看来这不是在每台机器上都可以重现的,如果您设法重现该问题,请发表评论说。
我已经设法在以下方面重现了该问题:
- 3x 64 位 Windows 7 机器运行 i7-2600
- 运行 i7-3630QM 的 64 位 Windows 8 机器
我无法重现以下问题:
- 运行 i5-2500k 的 64 位 Windows 8 机器
更新 2
我已经向 Microsoft here 提交了一个错误,但是到目前为止他们无法重现,所以如果尽可能多的人可以尝试运行示例项目,这将非常有帮助,它可以在附件选项卡上找到链接的问题。
【问题讨论】:
-
你在哪个框架上运行? .NET 4.5?单声道?
-
我应该提到的是,.NET 4.5 添加了一个标签,以防万一这是 .NET 框架的问题。
-
你为什么用 BCL 标记它?
-
因为我怀疑这可能是 BCL 的一部分
SemaphoreSlim中的错误。 -
感谢@Noseratio 的链接,我已将此报告为错误,here is the link
标签: c# .net-4.5 async-await semaphore base-class-library