1
0
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:
James Carter 2025-02-24 07:33:26 +00:00 committed by GitHub
parent 4c050744ad
commit b13cff5a95
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 36 additions and 28 deletions

View File

@ -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));
}

View File

@ -32,21 +32,21 @@ 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)
{
CancellationTokenRegistration registration = default;
try
{
Task<bool> waiter = _completed;
lock (_waits)
{
if (_signaled)
{
if(_reset)
if (_reset)
_signaled = false;
return _completed;
}
else
else if (!ct.IsCancellationRequested)
{
if (ct.IsCancellationRequested)
return _completed;
var tcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
if (timeout.HasValue)
{
@ -55,7 +55,7 @@ namespace CryptoExchange.Net.Objects
ct = cancellationSource.Token;
}
var registration = ct.Register(() =>
registration = ct.Register(() =>
{
lock (_waits)
{
@ -68,9 +68,16 @@ namespace CryptoExchange.Net.Objects
_waits.Enqueue(tcs);
return tcs.Task;
waiter = tcs.Task;
}
}
return await waiter.ConfigureAwait(false);
}
finally
{
registration.Dispose();
}
}
/// <summary>