Background:
I have a "Messenger" class. It sends messages. But due to limitations, let's say it can only send - at most - 5 messages at a time.
I have a WPF application which queues messages as needed, and waits for the queued message to be handled before continuing. Due to the asynchronous nature of the application, any number of messages could be await
ed at any given time.
Current Implementation:
To accomplish this, I've implemented a Task<Result> SendMessage(Message message)
API within my messaging class. Internal to the messaging class is a custom TaskScheduler (the LimitedConcurrencyTaskScheduler from MSDN), with its concurrency level set to 5. In this way, I would expect that no matter how many messages are queued, only 5 will be sent out at a time, and my client application will patiently wait until its respective message has been handled.
Problem:
When I await
the SendMessage
method, I can see via the debugger that the message was completed and the result returned, but my code never executes beyond the await
ed method call!
Is there some special considerations that need to be made, when await
ing a Task which was scheduled using a different TaskScheduler?
Snipped Code:
From my client/consuming function:
public async Task Frobulate()
{
Message myMessage = new Message(x, y, z);
await messenger.SendMessage(myMessage);
//Code down here never executes!
}
From my messenger class:
private TaskScheduler _messengerTaskScheduler = new LimitedConcurrencyLevelTaskScheduler(5);
private TaskFactory _messengerTaskFactory = new TaskFactory(_messengerScheduler);
public Task<Result> SendMessage(Message message)
{
//My debugger has verified that "InternalSendMessage" has completed,
//but the caller's continuation appears to never execute
return _messengerTaskFactory.StartNew(() => InternalSendMessage(message));
}
Update:
The 'freeze' does not actually appear to be caused by my custom TaskScheduler
; when I queue up the Task
with the default TaskFactory
, the same behavior occurs! There must be something else happening at a more fundamental level, likely due to my own stupidity.
Based on the comments, you probably have a deadlock because you're blocking on async code.
When using async, whenever there are thread restrictions on the SynchronizationContext
or TaskScheduler
and the code blocks using Task.Result
or Task.Wait
there's a possibility of deadlocking. The asynchronous operation needs a thread to finish execution, which it can't get because the SynchronizationContext
(or TaskScheduler
in your case) is waiting for that same exact operation to complete before allowing "new" ones to run.
Go deeper in Stephen Cleary's blog post: Don't Block on Async Code
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With