- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
在我们的一个类(class)中,我们大量使用 SemaphoreSlim.WaitAsync(CancellationToken)
并取消它。
当对 WaitAsync
的挂起调用在调用 SemaphoreSlim.Release()
后不久被取消时,我似乎遇到了问题(很快,我的意思是在 ThreadPool
有机会处理排队的项目之前),它将信号量置于无法获取进一步锁定的状态。
由于 ThreadPool
项是否在调用 Release()
和 Cancel()
之间执行的不确定性,以下示例并不总能说明问题,对于那些情况,我已明确表示要忽略该运行。
这是我试图证明问题的例子:
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
的取消不再允许任何线程进入。
更新
看来这并不是在每台机器上都可以重现,如果您设法重现该问题,请发表评论说明。
我已经成功重现了以下问题:
我无法重现以下问题:
更新 2
我已向 Microsoft 提交错误 here ,但是到目前为止,他们无法重现,所以如果尽可能多的人可以尝试运行示例项目,那将非常有帮助,它可以在链接问题的附件选项卡上找到。
最佳答案
SemaphoreSlim 在 .NET 4.5.1 中发生了变化
.NET 4.5 版本的 WaitUntilCountOrTimeoutAsync 方法是:
private async Task<bool> WaitUntilCountOrTimeoutAsync(TaskNode asyncWaiter, int millisecondsTimeout, CancellationToken cancellationToken)
{
[...]
// If the await completed synchronously, we still hold the lock. If it didn't,
// we no longer hold the lock. As such, acquire it.
lock (m_lockObj)
{
RemoveAsyncWaiter(asyncWaiter);
if (asyncWaiter.IsCompleted)
{
Contract.Assert(asyncWaiter.Status == TaskStatus.RanToCompletion && asyncWaiter.Result,
"Expected waiter to complete successfully");
return true; // successfully acquired
}
cancellationToken.ThrowIfCancellationRequested(); // cancellation occurred
return false; // timeout occurred
}
}
4.5.1同方法:
private async Task<bool> WaitUntilCountOrTimeoutAsync(TaskNode asyncWaiter, int millisecondsTimeout, CancellationToken cancellationToken)
{
[...]
lock (m_lockObj)
{
if (RemoveAsyncWaiter(asyncWaiter))
{
cancellationToken.ThrowIfCancellationRequested();
return false;
}
}
return await asyncWaiter.ConfigureAwait(false);
}
asyncWaiter 基本上是一个始终返回 true 的任务(在单独的线程中完成,始终返回 True 结果)。
Release 方法调用 RemoveAsyncWaiter 并安排 worker 以 true 完成。
这是 4.5 中可能出现的问题:
RemoveAsyncWaiter(asyncWaiter);
if (asyncWaiter.IsCompleted)
{
Contract.Assert(asyncWaiter.Status == TaskStatus.RanToCompletion && asyncWaiter.Result,
"Expected waiter to complete successfully");
return true; // successfully acquired
}
//! another thread calls Release
//! asyncWaiter completes with true, Wait should return true
//! CurrentCount will be 0
cancellationToken.ThrowIfCancellationRequested(); // cancellation occurred,
//! throws OperationCanceledException
//! wasCanceled will be true
return false; // timeout occurred
在 4.5.1 中,RemoveAsyncWaiter 将返回 false,而 WaitAsync 将返回 true。
关于c# - 取消SemaphoreSlim.WaitAsync保持信号量锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21019895/
我想知道是否SemaphoreSlim调用 Await 时具有优先级之类的东西。 我找不到任何东西,但也许以前有人做过这样的事情。 这个想法是,如果我需要,可以稍后以更高的优先级在信号量上调用等待,并
Documentation说: The SemaphoreSlim class represents a lightweight, fast semaphore that can be used fo
目前,我正在努力实现 SemaphoreSlim 以“锁定”必须是线程安全的方法的“部分”。我的问题是,在没有异常处理过载的情况下实现它是非常困难的。因为在释放“锁”之前抛出异常时,它将永远留在那里。
我创建了以下方法 TestThrottled 来尝试限制我的任务,但它根本没有限制,当我调用 WhenAll 并且此方法都具有相同的耗时时。我做错了什么吗? private static as
我们正在使用 .NET 4.5.1 开发一个应用程序,并在后台使用 SemaphoreSlim 实现了我自己的“异步锁”。要锁定,我们使用以下方法: public async Task LockAsy
semaphore 的真正力量是: Limits the number of threads that can access a resource or pool of resources concu
我在 .NET Core (2.2) 中使用 SemaphoreSlim 类时遇到问题,希望有人可以提供帮助。 我有一个 API 方法 (AddBooking),它将预订添加到数据库,此方法包括 3
概括 我有一个使用 lock 的类(class)提供对私有(private)字段的线程安全访问。但是,由于下面详述的原因,我正在考虑改用 SemaphoreSlim实现线程安全。我知道如果我用 loc
为了同步,我创建了一个 SemaphoreSlim(1)。 这意味着如果我在我的类中有这个信号量的单个实例作为锁: private SemaphoreSlim _initializationSemap
我正在尝试使用新的 SemaphoreSlim .NET 4.0 中的类来限制可以无限期运行的快节奏循环的速率。在对此进行单元测试时,我发现如果循环足够紧密且并行度足够高,SemaphoreSlim当
这个有效: int _counter; readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); async void Button_C
using System; using System.Threading; using System.Threading.Tasks; namespace ConsoleApp2 { clas
我对 await 关键字的理解是,await 限定语句之后的代码在完成后作为该语句的延续运行。 因此以下两个版本应该产生相同的输出: public static Task Run(Semaph
class Program { static IEnumerable list = Enumerable.Range(1, 10).Select(i => new site(i.ToStrin
我在 Async/Await 函数中有一部分代码,我希望一次只执行一个线程。 这相对简单,只需创建一个新的 SemaphoreSlim(1) 并使用 WaitAsync/Release。效果是第一个线
根据文档: "a SemaphoreSlim doesn't use a Windows kernel semaphore". SemaphoreSlim 是否使用了任何特殊资源,这使得在不再使用 S
SemaphoreSlim 的文档说“只有在所有其他操作都已完成时才应使用 Dispose”。 应该如何调整以下类,以便线程 B 可以在线程 A 等待 Async() 时调用 Dispose()。调用
附加问题 SemaphoreSlim(1, 1) 是否仍然确保我有正确的输出 1000000,即使 task1 和 task2 在 2 个不同的平台上运行核心? 原始问题 考虑以下代码片段,_sema
我最近开始学习 C#,但在更新 UI 时遇到了运行多线程的问题。根据我目前所学,SemaphoreSlim 似乎是运行多线程同时仍控制最大并发线程数的正确方法。 场景:我想向网站(例如http://w
我遇到了一个问题,我需要限制对另一个网络服务器的调用次数。它会有所不同,因为服务器是共享的,并且可能具有更多或更少的容量。 我正在考虑使用 SemaphoreSlim 类,但没有公共(public)属
我是一名优秀的程序员,十分优秀!