@@ -12,7 +12,10 @@ namespace MQTTnet.Internal | |||||
private bool isSignaled; | private bool isSignaled; | ||||
public AsyncAutoResetEvent(bool signaled = false) | |||||
public AsyncAutoResetEvent() : this(false) | |||||
{ } | |||||
public AsyncAutoResetEvent(bool signaled) | |||||
{ | { | ||||
this.isSignaled = signaled; | this.isSignaled = signaled; | ||||
} | } | ||||
@@ -56,7 +59,7 @@ namespace MQTTnet.Internal | |||||
} | } | ||||
} | } | ||||
Task winner = await Task.WhenAny(tcs.Task, Task.Delay(timeout, cancellationToken)); | |||||
Task winner = await Task.WhenAny(tcs.Task, Task.Delay(timeout, cancellationToken)).ConfigureAwait(false); | |||||
if (winner == tcs.Task) | if (winner == tcs.Task) | ||||
{ | { | ||||
// The task was signaled. | // The task was signaled. | ||||
@@ -68,7 +71,7 @@ namespace MQTTnet.Internal | |||||
// This is an O(n) operation since waiters is a LinkedList<T>. | // This is an O(n) operation since waiters is a LinkedList<T>. | ||||
lock (this.waiters) | lock (this.waiters) | ||||
{ | { | ||||
bool removed = this.waiters.Remove(tcs); | |||||
this.waiters.Remove(tcs); | |||||
if (winner.Status == TaskStatus.Canceled) | if (winner.Status == TaskStatus.Canceled) | ||||
{ | { | ||||
throw new OperationCanceledException(cancellationToken); | throw new OperationCanceledException(cancellationToken); | ||||
@@ -5,7 +5,7 @@ using System.Threading.Tasks; | |||||
namespace MQTTnet.Internal | namespace MQTTnet.Internal | ||||
{ | { | ||||
// From Stephen Toub (https://blogs.msdn.microsoft.com/pfxteam/2012/02/12/building-async-coordination-primitives-part-6-asynclock/) | // From Stephen Toub (https://blogs.msdn.microsoft.com/pfxteam/2012/02/12/building-async-coordination-primitives-part-6-asynclock/) | ||||
public sealed class AsyncLock | |||||
public sealed class AsyncLock : IDisposable | |||||
{ | { | ||||
private readonly SemaphoreSlim m_semaphore = new SemaphoreSlim(1, 1); | private readonly SemaphoreSlim m_semaphore = new SemaphoreSlim(1, 1); | ||||
private readonly Task<IDisposable> m_releaser; | private readonly Task<IDisposable> m_releaser; | ||||
@@ -25,6 +25,11 @@ namespace MQTTnet.Internal | |||||
TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); | TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); | ||||
} | } | ||||
public void Dispose() | |||||
{ | |||||
this.m_semaphore?.Dispose(); | |||||
} | |||||
private sealed class Releaser : IDisposable | private sealed class Releaser : IDisposable | ||||
{ | { | ||||
private readonly AsyncLock m_toRelease; | private readonly AsyncLock m_toRelease; | ||||
@@ -10,7 +10,7 @@ namespace MQTTnet.Core.Tests | |||||
// Inspired from the vs-threading tests (https://github.com/Microsoft/vs-threading/blob/master/src/Microsoft.VisualStudio.Threading.Tests/AsyncAutoResetEventTests.cs) | // Inspired from the vs-threading tests (https://github.com/Microsoft/vs-threading/blob/master/src/Microsoft.VisualStudio.Threading.Tests/AsyncAutoResetEventTests.cs) | ||||
public class AsyncAutoResetEventTests | public class AsyncAutoResetEventTests | ||||
{ | { | ||||
private AsyncAutoResetEvent evt; | |||||
private readonly AsyncAutoResetEvent evt; | |||||
public AsyncAutoResetEventTests() | public AsyncAutoResetEventTests() | ||||
{ | { | ||||
@@ -57,7 +57,7 @@ namespace MQTTnet.Core.Tests | |||||
for (int i = 0; i < waiters.Length; i++) | for (int i = 0; i < waiters.Length; i++) | ||||
{ | { | ||||
this.evt.Set(); | this.evt.Set(); | ||||
await waiters[i]; | |||||
await waiters[i].ConfigureAwait(false); | |||||
} | } | ||||
} | } | ||||
@@ -139,7 +139,7 @@ namespace MQTTnet.Core.Tests | |||||
Assert.IsFalse(waitTask.IsCompleted); | Assert.IsFalse(waitTask.IsCompleted); | ||||
// Cancel the request and ensure that it propagates to the task. | // Cancel the request and ensure that it propagates to the task. | ||||
await Task.Delay(1000); | |||||
await Task.Delay(1000).ConfigureAwait(false); | |||||
try | try | ||||
{ | { | ||||
waitTask.GetAwaiter().GetResult(); | waitTask.GetAwaiter().GetResult(); | ||||