mirror of
https://github.com/JKorf/CryptoExchange.Net
synced 2025-06-07 07:56:12 +00:00
Fix memory leak in AsyncAutoResetEvent (#229)
* Fix memory leak in AsyncAutoResetEvent CancellationTokenRegistration MUST be disposed, as the CancellationToken passed is saved for the lifetime of the Client, and registrations build up forever.
This commit is contained in:
parent
4c050744ad
commit
b13cff5a95
@ -106,6 +106,7 @@ namespace CryptoExchange.Net.UnitTests
|
||||
for(var i = 1; i <= 10; i++)
|
||||
{
|
||||
evnt.Set();
|
||||
await Task.Delay(1); // Wait for the continuation.
|
||||
Assert.That(10 - i == waiters.Count(w => w.Status != TaskStatus.RanToCompletion));
|
||||
}
|
||||
|
||||
|
@ -32,44 +32,51 @@ namespace CryptoExchange.Net.Objects
|
||||
/// Wait for the AutoResetEvent to be set
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Task<bool> WaitAsync(TimeSpan? timeout = null, CancellationToken ct = default)
|
||||
public async Task<bool> WaitAsync(TimeSpan? timeout = null, CancellationToken ct = default)
|
||||
{
|
||||
lock (_waits)
|
||||
CancellationTokenRegistration registration = default;
|
||||
try
|
||||
{
|
||||
if (_signaled)
|
||||
Task<bool> waiter = _completed;
|
||||
lock (_waits)
|
||||
{
|
||||
if(_reset)
|
||||
_signaled = false;
|
||||
return _completed;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ct.IsCancellationRequested)
|
||||
return _completed;
|
||||
|
||||
var tcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
if (timeout.HasValue)
|
||||
if (_signaled)
|
||||
{
|
||||
var timeoutSource = new CancellationTokenSource(timeout.Value);
|
||||
var cancellationSource = CancellationTokenSource.CreateLinkedTokenSource(timeoutSource.Token, ct);
|
||||
ct = cancellationSource.Token;
|
||||
if (_reset)
|
||||
_signaled = false;
|
||||
}
|
||||
|
||||
var registration = ct.Register(() =>
|
||||
else if (!ct.IsCancellationRequested)
|
||||
{
|
||||
lock (_waits)
|
||||
var tcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
if (timeout.HasValue)
|
||||
{
|
||||
tcs.TrySetResult(false);
|
||||
|
||||
// Not the cleanest but it works
|
||||
_waits = new Queue<TaskCompletionSource<bool>>(_waits.Where(i => i != tcs));
|
||||
var timeoutSource = new CancellationTokenSource(timeout.Value);
|
||||
var cancellationSource = CancellationTokenSource.CreateLinkedTokenSource(timeoutSource.Token, ct);
|
||||
ct = cancellationSource.Token;
|
||||
}
|
||||
}, useSynchronizationContext: false);
|
||||
|
||||
registration = ct.Register(() =>
|
||||
{
|
||||
lock (_waits)
|
||||
{
|
||||
tcs.TrySetResult(false);
|
||||
|
||||
// Not the cleanest but it works
|
||||
_waits = new Queue<TaskCompletionSource<bool>>(_waits.Where(i => i != tcs));
|
||||
}
|
||||
}, useSynchronizationContext: false);
|
||||
|
||||
|
||||
_waits.Enqueue(tcs);
|
||||
return tcs.Task;
|
||||
_waits.Enqueue(tcs);
|
||||
waiter = tcs.Task;
|
||||
}
|
||||
}
|
||||
|
||||
return await waiter.ConfigureAwait(false);
|
||||
}
|
||||
finally
|
||||
{
|
||||
registration.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user