1565 high cpu load from asyncsignal (#1566)

This commit is contained in:
Christian
2022-11-09 19:56:29 +01:00
committed by GitHub
parent 5c74728387
commit 5ee0bb4b65
6 changed files with 67 additions and 20 deletions
+18 -12
View File
@@ -29,7 +29,7 @@ namespace MQTTnet.Internal
{
lock (_syncRoot)
{
_signal?.Dispose();
_signal.Dispose();
_isDisposed = true;
}
@@ -48,10 +48,10 @@ namespace MQTTnet.Internal
{
if (_queue.TryDequeue(out var item))
{
return new AsyncQueueDequeueResult<TItem>(true, item);
return AsyncQueueDequeueResult<TItem>.Success(item);
}
return new AsyncQueueDequeueResult<TItem>(false, default);
return AsyncQueueDequeueResult<TItem>.NonSuccess;
}
public async Task<AsyncQueueDequeueResult<TItem>> TryDequeueAsync(CancellationToken cancellationToken)
@@ -60,36 +60,42 @@ namespace MQTTnet.Internal
{
try
{
Task task;
Task task = null;
lock (_syncRoot)
{
if (_isDisposed)
{
return new AsyncQueueDequeueResult<TItem>(false, default);
return AsyncQueueDequeueResult<TItem>.NonSuccess;
}
task = _signal.WaitAsync(cancellationToken);
if (_queue.IsEmpty)
{
task = _signal.WaitAsync(cancellationToken);
}
}
await task.ConfigureAwait(false);
if (task != null)
{
await task.ConfigureAwait(false);
}
if (cancellationToken.IsCancellationRequested)
{
return new AsyncQueueDequeueResult<TItem>(false, default);
return AsyncQueueDequeueResult<TItem>.NonSuccess;
}
if (_queue.TryDequeue(out var item))
{
return new AsyncQueueDequeueResult<TItem>(true, item);
return AsyncQueueDequeueResult<TItem>.Success(item);
}
}
catch (OperationCanceledException)
{
return new AsyncQueueDequeueResult<TItem>(false, default);
return AsyncQueueDequeueResult<TItem>.NonSuccess;
}
}
return new AsyncQueueDequeueResult<TItem>(false, default);
return AsyncQueueDequeueResult<TItem>.NonSuccess;
}
}
}
@@ -4,8 +4,10 @@
namespace MQTTnet.Internal
{
public class AsyncQueueDequeueResult<TItem>
public sealed class AsyncQueueDequeueResult<TItem>
{
public static readonly AsyncQueueDequeueResult<TItem> NonSuccess = new AsyncQueueDequeueResult<TItem>(false, default);
public AsyncQueueDequeueResult(bool isSuccess, TItem item)
{
IsSuccess = isSuccess;
@@ -15,5 +17,10 @@ namespace MQTTnet.Internal
public bool IsSuccess { get; }
public TItem Item { get; }
public static AsyncQueueDequeueResult<TItem> Success(TItem item)
{
return new AsyncQueueDequeueResult<TItem>(true, item);
}
}
}
+23 -3
View File
@@ -33,9 +33,17 @@ namespace MQTTnet.Internal
{
_isSignaled = true;
Cleanup();
// If there is already a waiting task let it run.
_waiter?.Approve();
_waiter = null;
if (_waiter != null)
{
_waiter.Approve();
_waiter = null;
// Since we already got a waiter the signal must be reset right now!
_isSignaled = false;
}
}
}
@@ -47,8 +55,11 @@ namespace MQTTnet.Internal
{
ThrowIfDisposed();
Cleanup();
if (_isSignaled)
{
_isSignaled = false;
return CompletedTask.Instance;
}
@@ -58,7 +69,7 @@ namespace MQTTnet.Internal
{
throw new InvalidOperationException("Only one waiting task is permitted per async signal.");
}
_waiter.Dispose();
}
@@ -67,6 +78,15 @@ namespace MQTTnet.Internal
}
}
void Cleanup()
{
// Cleanup if the previous waiter was cancelled.
if (_waiter != null && _waiter.Task.IsCanceled)
{
_waiter = null;
}
}
void ThrowIfDisposed()
{
if (_isDisposed)