This method is often stuck in method private async Task CloseAsync()
See original GitHub issueDescription
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:
- Created 2 years ago
- Comments:7 (3 by maintainers)
Top 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 >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
@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 hasSynchronizationContext
set up.TdClient::Dispose
blocks onCloseSynchronously()
which, in turn, callsthis.CloseAsync().GetAwaiter().GetResult()
: https://github.com/egramtel/tdsharp/blob/0fcd3a6839764674d79e75818d85ab2e10ea2f04/TDLib/TdClient.cs#L226-L229So, your UI thread is blocked by a synchronous call to
Dispose
, andDispose
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:
Replace
this.tdClient.Dispose()
withWithNullSynchronizationContext(() => this.tdClient.Dispose())
Write the following method:
This will temporarily override the
SynchronizationContext
for the method to use the thread pool instead of the current synchronization context.ths very much