Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sometimes AsyncContext would not stop #242

Open
szmcdull opened this issue Nov 13, 2021 · 4 comments
Open

Sometimes AsyncContext would not stop #242

szmcdull opened this issue Nov 13, 2021 · 4 comments
Assignees

Comments

@szmcdull
Copy link

I understand that AsyncContext would not stop until all tasks are finished. I want to find out which tasks are out running. But I didn't find out a good way. Both the Tasks view and Parallel Stacks view didn't help. Then I found something strange, the _outstandingOperations is not matching with _queue.Count
image
I read the source but didn't find any clue. Can you help me?

@StephenCleary
Copy link
Owner

I want to find out which tasks are out running.

Unfortunately, AsyncEx can't help you with that, since it doesn't have that information.

the _outstandingOperations is not matching with _queue.Count

The _outstandingOperations tracks the number of "operations" that have been registered with the SynchronizationContext. Depending on how you use AsyncContext, it may use 0 or 1 internally, and the rest represent async void methods. The _queue is the continuations that have been queued to the AsyncContext. These track different kinds of asynchronous operations and aren't supposed to be the same.

If the screenshot you posted is at a time when you expected the AsyncContext to be complete, then you can conclude that since _outstandingOperations is 3, then there are at least two async void methods that have not completed.

@szmcdull
Copy link
Author

By async void do you mean async void Func(...)? I see _outstandingOperations is increased from AsyncContext.TaskScheduler.Enqueue(Task). These Tasks are mainly completion callbacks from other threads than the main thread, for example, timer or socket callbacks.

        private void Enqueue(Task task, bool propagateExceptions)
        {
            OperationStarted();
            task.ContinueWith(_ => OperationCompleted(), CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, _taskScheduler);
            _queue.TryAdd(task, propagateExceptions);
tSynchronizationContext(WinFormsSynchronizationContext).
        }

        private void OperationCompleted()
        {
            var newCount = Interlocked.Decrement(ref _outstandingOperations);
            if (newCount == 0)
                _queue.CompleteAdding();
        }

        public void Execute()
        {
            SynchronizationContextSwitcher.ApplyContext(_synchronizationContext, () =>
            {
                var tasks = _queue.GetConsumingEnumerable();
                foreach (var task in tasks)
                {
                    _taskScheduler.DoTryExecuteTask(task.Item1);

                    // Propagate exception if necessary.
                    if (task.Item2)
                        task.Item1.WaitAndUnwrapException();
                }
            });
        }

This is where _outstandingOperations is mainly increased and decreased (the other 2 is in AsyncContext.Run). Seems _outstandingOperations is highly bound with _queue. Each time _outstandingOperations is increased a task will be added to the queue. The task will be then popped from the queue and executed. When it is complete, the counter decreases.

@szmcdull
Copy link
Author

szmcdull commented Nov 15, 2021

OK I found out that AsyncVoidMethodBuilder does call SynchronizationContext.OperationStarted.

Anyway, I decide to forcefully decrease _outstandingOperations when I believe my program should exit, using reflection haha

@StephenCleary
Copy link
Owner

Ah, I forgot that it's also used in Enqueue.

I decide to forcefully decrease _outstandingOperations when I believe my program should exit, using reflection

I strongly recommend against this. I recommend finding what code isn't completing and ensure it completes, instead.

@StephenCleary StephenCleary self-assigned this Nov 15, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants