I have a service that ensures that exactly one popup is displayed at the same time. AddPopupAsync
can be called concurrently, i.e. a popup is open while another 10 AddPopupAsync
requests drop in. The code:
public async Task<int> AddPopupAsync(Message message)
{
//[...]
while (popupQueue.Count != 0)
{
await popupQueue.Peek();
}
return await Popup(interaction);
}
But I can spot two unwanted things that can happen because of the lack of thread safety:
- If the queue is empty, Peek will throw an exception
- If a thread A is preempted before the first statement in Popup, another thread B will not wait for the pending popup A since the queue is still empty.
Popup method works with a TaskCompletionSource
and before calling its SetResult
method, popupQueue.Dequeue()
is called.
I think about using the atomic TryPeek
from ConcurrentQueue
in order to make #1 thread safe:
do
{
Task<int> result;
bool success = popupQueue.TryPeek(out result);
if (!success) break;
await result;
}
while (true);
Then I read about a AsyncProducerConsumerCollection but I'm not sure if that is the most simple solution.
How can I ensure thread safety in a simple way? Thank you.