我有一个服务,可以确保同一时间只显示一个弹出窗口。可以并发调用AddPopupAsync
,也就是说,当一个弹出窗口打开时,另外10个AddPopupAsync
请求会同时到来。代码如下:
public async Task<int> AddPopupAsync(Message message)
{
//[...]
while (popupQueue.Count != 0)
{
await popupQueue.Peek();
}
return await Popup(interaction);
}
然而,由于缺乏线程安全性,可能会发生两种不希望发生的情况:
- 如果队列为空,则 Peek 将抛出异常
- 如果线程 A 在 Popup 中的第一条语句之前被抢占,另一个线程 B 将不会等待挂起的 Popup A,因为队列仍然为空。
Popup 方法使用 TaskCompletionSource,在调用其 SetResult 方法之前,会调用 popupQueue.Dequeue()。
我考虑使用 ConcurrentQueue 中的原子 TryPeek 以使 #1 线程安全:
do
{
Task<int> result;
bool success = popupQueue.TryPeek(out result);
if (!success) break;
await result;
}
while (true);
我读到了一个AsyncProducerConsumerCollection,但我不确定这是否是最简单的解决方案。
有什么简单的方法可以确保线程安全吗?谢谢。
ConcurrentQueue<T>
内置了你所需要的功能。 - Yuval ItzchakovAddPopupAsync
,这样做不是很合理吗? - Stephen Clearyawait
不会引入工作线程。除非你从 其他线程 调用AddPopupAsync
,否则它不需要是线程安全的。了解有关async
如何工作的更多信息,请查看我的async
简介。 - Stephen Cleary