use*_*276 5 .net c# thread-safety async-await
我有一个服务,确保同时显示一个弹出窗口.AddPopupAsync
可以同时调用,即弹出窗口打开而另外10个AddPopupAsync
请求丢失.代码:
public async Task<int> AddPopupAsync(Message message)
{
//[...]
while (popupQueue.Count != 0)
{
await popupQueue.Peek();
}
return await Popup(interaction);
}
Run Code Online (Sandbox Code Playgroud)
但是由于缺乏线程安全性,我可以发现可能发生的两件不需要的事情:
Popup方法与a一起使用TaskCompletionSource
,在调用其SetResult
方法之前,调用它popupQueue.Dequeue()
.
我考虑使用原子弹TryPeek
从ConcurrentQueue
为了使#1线程安全的:
do
{
Task<int> result;
bool success = popupQueue.TryPeek(out result);
if (!success) break;
await result;
}
while (true);
Run Code Online (Sandbox Code Playgroud)
然后我读到了AsyncProducerConsumerCollection,但我不确定这是否是最简单的解决方案.
如何以简单的方式确保线程安全?谢谢.
要简单地添加线程安全性,您应该使用a ConcurrentQueue
.它是队列的线程安全实现,您可以像使用队列一样使用它而不必担心并发.
但是,如果你想要一个队列,你可以await
异步(这意味着你没有忙等待或在等待时阻塞一个线程)你应该使用TPL Dataflow BufferBlock
,它与AsyncProducerConsumerCollection
MS已经为你实现的非常类似:
var buffer = new BufferBlock<int>();
await buffer.SendAsync(3); // Instead of enqueue.
int item = await buffer.ReceiveAsync(); // instead of dequeue.
Run Code Online (Sandbox Code Playgroud)
ConcurrentQueue
对于线程安全性很好,但在高级别的争用中浪费.BufferBlock
它不仅是线程安全的,它还为您提供异步协调(通常在消费者和生产者之间).