"Waiting" does not return when my task starts from a custom TaskScheduler

Background:

I have a class "Messenger". He sends messages. But due to restrictions, let's say he can only send messages - no more than - 5 at a time.

I have a WPF application that queues messages if necessary, and waits for a message with a queue to be processed before continuing. Due to the asynchronous nature of the application, any number of messages can be await ed at any given time.

Current implementation:

To do this, I implemented the Task<Result> SendMessage(Message message) API in my message class. Internal to the messaging class is a custom TaskScheduler ( LimitedConcurrencyTaskScheduler from MSDN ), with a concurrency level set to 5. Thus, I will expect that only 5 will be sent regardless of the number of messages in the queue, and my client application will wait patiently until the corresponding message will not be processed.

Problem:

When I await the SendMessage method, I can see through the debugger that the message was completed and the result was returned, but my code is never executed after the await ed method is await !

Are there any special considerations to be made when await task that was scheduled using another TaskScheduler?

Code taken:

From my customer / consumer 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 continuation appears to never execute return _messengerTaskFactory.StartNew(() => InternalSendMessage(message)); } 

Update:

The β€œfreeze” is not actually caused by my custom TaskScheduler ; when I queue Task for the default TaskFactory , the same behavior happens! Something else must be happening on a more fundamental level, probably due to my own stupidity.

+6
source share
1 answer

Based on the comments, you probably have a dead end because you are blocking asynchronous code.

When using async, when there are thread restrictions for SynchronizationContext or TaskScheduler , and code blocks using Task.Result or Task.Wait , there is the possibility of blocking. An asynchronous operation requires a thread to complete execution, which it cannot receive, because the SynchronizationContext (or TaskScheduler in your case) waits for the completion of this exact operation before allowing the launch of the "new" ones.

Go deeper into Stephen Cleary's blog post: Don't block asynchronous code

+3
source

Source: https://habr.com/ru/post/970818/


All Articles