question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

This method is often stuck in method private async Task CloseAsync()

See original GitHub issue

Description

This method is often stuck in the synchronization method Dispose()

await ExecuteAsync(new TdApi.Close());
await Task.WhenAny(tcs.Task, Task.Delay(TimeoutToClose));
// This task has been waiting for a long time, causing it to be unable to Dispose()

Because there is a lock (The problem is not this ) (This is the earliest investigation)

  • here is Code

        /// <summary>
        /// Disposes client and json client
        /// Updates are stopped from being sent to updates handler
        /// </summary>
        public void Dispose()
        {
            lock (_disposeLock)
            {
                if (_receiver == null || _tdJsonClient == null)
                {
                    return;
                }
            
                CloseSynchronously();
            
                _receiver.Dispose();
                _receiver.Received -= OnReceived;
                _receiver.AuthorizationStateChanged -= OnAuthorizationStateChanged;
                _receiver = null;
            
                _tdJsonClient.Dispose();
                _tdJsonClient = null;
            }
        }
  • Tracking found that the problem occurred in this method (await Task.WhenAny(tcs.Task, Task.Delay(TimeoutToClose))😉 The final problem is here
  • await Task.WhenAny(tcs.Task, Task.Delay(TimeoutToClose));

//here...
// await ExecuteAsync(new TdApi.Close()); his task has been waiting for a long time, causing it to be unable to Dispose()
//await Task.WhenAny(tcs.Task, Task.Delay(TimeoutToClose));

 private async Task CloseAsync()
        {
            var tcs = new TaskCompletionSource<TdApi.AuthorizationState>(TaskCreationOptions.RunContinuationsAsynchronously);

            EventHandler<TdApi.AuthorizationState> handler = (sender, state) =>
            {
                if (state is TdApi.AuthorizationState.AuthorizationStateClosed)
                {
                    tcs.SetResult(state);
                }
            };
            
            try
            {
                _receiver.AuthorizationStateChanged += handler;
                
                if (_authorizationState is TdApi.AuthorizationState.AuthorizationStateClosed)
                {
                    return;
                }

                Console.WriteLine("------------------------>Close() Begin");

               //in here ...I found that I couldn't respond for a long time and I continued to debug.
              //this task has been waiting for a long time, causing it to be unable to Dispose()
              //this task has been waiting for a long time, causing it to be unable to Dispose()
                await ExecuteAsync(new TdApi.Close());
  


                Console.WriteLine("------------------------>Close() End");

                Console.WriteLine("------------------------>Task.WhenAny() Begin"); 


// TaskCompletionSource
               //this task has been waiting for a long time, causing it to be unable to Dispose()
              //this task has been waiting for a long time, causing it to be unable to Dispose()
                await Task.WhenAny(tcs.Task, Task.Delay(TimeoutToClose));


                Console.WriteLine("------------------------>Task.WhenAny() Begin");


            }
            finally
            {
                _receiver.AuthorizationStateChanged -= handler;
            }
        }
  • i test it is still… can not
 await Task.WhenAny(tcs.Task, Task.Delay(1000));

How to solve it well and Dispose it

  • Or forced Dispose
_tdClient.Dispose();
_tdClient.Dispose();
_tdClient.Dispose();

//Or forced Dispose

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:7 (3 by maintainers)

github_iconTop GitHub Comments

4reactions
ForNeVeRcommented, Nov 1, 2021

@AtlantisDe, I am sorry for the delay, but I was finally able to investigate this peculiar case.

It turns out the situation is pretty simple. It is a classical deadlock caused by GetAwaiter().GetResult().

You are calling TdClient::Dispose on the UI thread. I.e. your thread has SynchronizationContext set up. TdClient::Dispose blocks on CloseSynchronously() which, in turn, calls this.CloseAsync().GetAwaiter().GetResult(): https://github.com/egramtel/tdsharp/blob/0fcd3a6839764674d79e75818d85ab2e10ea2f04/TDLib/TdClient.cs#L226-L229

So, your UI thread is blocked by a synchronous call to Dispose, and Dispose waits for the call you mentioned, await Task.WhenAny(tcs.Task, Task.Delay(TimeoutToClose)), to resolve.

It will never happen, because await wants to schedule its continutation to run on the UI thread, and the UI thread is blocked.

For now, please use this workaround:

  1. Replace this.tdClient.Dispose() with WithNullSynchronizationContext(() => this.tdClient.Dispose())

  2. Write the following method:

    private static void WithNullSynchronizationContext(Action action)
    {
        var context = SynchronizationContext.Current;
        try
        {
            SynchronizationContext.SetSynchronizationContext(null);
            action();
        }
        finally
        {
            SynchronizationContext.SetSynchronizationContext(context);
        }
    }
    

This will temporarily override the SynchronizationContext for the method to use the thread pool instead of the current synchronization context.

0reactions
AtlantisDecommented, Nov 7, 2021

ths very much

Read more comments on GitHub >

github_iconTop Results From Across the Web

c# - Stuck at async method
In WinRT, we have to use HttpClient in async method, which I did as follows:- private async void update() { try { rawdata...
Read more >
Stuck at - await new Task<Object>(() => someObj)
I finally noticed that when you type, for example var readed = TcpClient.GetStream().ReadAsync() . That method was actually invoked and it reach ...
Read more >
Websocket close code. isPaused \n \n {Boolean} \n \n. Disable
The TryCloseNormally function closes the websocket connection from the server side. In order to communicate using the WebSocket protocol, you need to create...
Read more >
c# - Websockets client code and making it production-ready
The Timespan "Delay" is used to tell the server my client is OK and refreshes the subscription. Issuing this to the server too...
Read more >
Common async / Task mistakes, and how to avoid them
Looking at this code, the DoStuff() method waits for 1 second in whole. Since we don't await it directly but start both Tasks...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found