public void CancelStressTest() { foreach (bool sync in new[] { false, true }) { const int N = 64; long counter = 0; var mutex = new AsyncMutex(); Task[] tasks = Enumerable.Range(0, N).Select(_ => Inc()).ToArray(); Task.WaitAll(tasks); Assert.AreEqual(N, counter); async Task Inc() { while (true) { using (var cancel = new CancellationTokenSource()) { Task t = mutex.LockAsync(cancel.Token); await Task.Yield(); cancel.Cancel(); if (!t.IsCanceled) { await t; break; } } } long next = counter + 1; await Task.Yield(); counter = next; mutex.Unlock(runNextSynchronously: sync); } } }
public async Task LockAsync() { var mutex = new AsyncMutex(); await mutex.LockAsync(); mutex.Unlock(); }
public void Lock() { var mutex = new AsyncMutex(); mutex.Lock(); mutex.Unlock(); }
public void CancelTest() { var mutex = new AsyncMutex(); using (var cancel = new CancellationTokenSource()) { mutex.LockAsync().Wait(); Task t = mutex.LockAsync(cancel.Token); Assert.IsFalse(t.IsCompleted); mutex.Unlock(runNextSynchronously: true); t.Wait(); t = mutex.LockAsync(cancel.Token); cancel.Cancel(); Assert.AreEqual(TaskStatus.Canceled, t.Status); mutex.Unlock(runNextSynchronously: true); t = mutex.LockAsync(cancel.Token); Assert.AreEqual(TaskStatus.RanToCompletion, t.Status); } }
public void ExampleTest() { var expected = new[] { "Worker #0: 0", "Worker #1: 0", "Worker #1: 1", "Worker #1: 2", "Worker #0: 1", "Worker #0: 2", }; CollectionAssert.AreEqual(expected, Example().Result); async Task <List <string> > Example() { var res = new List <string>(); var mutex = new AsyncMutex(); await mutex.LockAsync(); Task[] tasks = Enumerable.Range(0, 2).Select(Work).ToArray(); mutex.Unlock(runNextSynchronously: true); await Task.WhenAll(tasks); return(res); async Task Work(int worker) { for (int i = 0; i != 3; ++i) { await mutex.LockAsync(); res.Add($"Worker #{worker}: {i}"); mutex.Unlock(runNextSynchronously: true); } } } }
public void FairnessTest() { foreach (bool sync in new[] { false, true }) { var mutex = new AsyncMutex(); var tasks = new Queue <Task>(Enumerable.Range(0, 1024).Select(_ => mutex.LockAsync())); while (tasks.Count > 0) { tasks.Enqueue(mutex.LockAsync()); for (int i = 0; i != 2; ++i) { tasks.Dequeue().Wait(); mutex.Unlock(sync); } } } }
public async Task MutualExclusion() { int sharedValue = 0; var mutex = new AsyncMutex(); var hundredEvent = new AsyncManualResetEvent(); // Create 10 threads that increment a value 10 times each for (int n = 0; n < 10; n++) { new Thread(async() => { await mutex.Lock(); int privateValue = sharedValue; for (int m = 0; m < 10; m++) { // If the mutex works, no other thread will increment sharedValue sharedValue++; privateValue++; Assert.Equal(privateValue, sharedValue); if (sharedValue == 100) { // The test case is complete hundredEvent.Set(); } // Yield the CPU to give other threads a chance to run await Task.Delay(10); } mutex.Unlock(); }).Start(); } await hundredEvent.WaitAsync(); Assert.Equal(100, sharedValue); }
public void LockUnlockStressTest() { foreach (bool sync in new[] { false, true }) { const int N = 64 << 10; long counter = 0; var mutex = new AsyncMutex(); Task.WhenAll(Enumerable.Range(0, N).Select(_ => Inc())).Wait(); Assert.AreEqual(N, counter); async Task Inc() { await mutex.LockAsync(); await Task.Yield(); long next = counter + 1; await Task.Yield(); counter = next; mutex.Unlock(runNextSynchronously: sync); } } }
public void LockUnlockBenchmark() { using (var cancel = new CancellationTokenSource()) { Console.WriteLine("Warmup:"); Benchmark(runNextSynchronously: false, cancelable: false, threads: 1024).Wait(); Benchmark(runNextSynchronously: false, cancelable: true, threads: 1024).Wait(); Benchmark(runNextSynchronously: true, cancelable: false, threads: 1024).Wait(); Benchmark(runNextSynchronously: true, cancelable: true, threads: 1024).Wait(); Console.WriteLine("\nThe real thing:"); foreach (bool sync in new[] { true, false }) { foreach (bool c in new[] { false, true }) { foreach (int threads in new[] { 1, 2, 4, 32, 1024 }) { Benchmark(runNextSynchronously: sync, cancelable: c, threads: threads).Wait(); } } } async Task Benchmark(bool runNextSynchronously, bool cancelable, int threads) { long counter = 0; var mutex = new AsyncMutex(); TimeSpan duration = TimeSpan.FromSeconds(1); Stopwatch stopwatch = Stopwatch.StartNew(); await Task.WhenAll(Enumerable.Range(0, threads).Select(_ => Inc())); double ns = 1e9 * stopwatch.Elapsed.TotalSeconds / counter; Console.WriteLine( " Benchmark(runNextSynchronously: {0,5}, cancelable: {1,5}, threads: {2,5:N0}): {3,7:N1} ns/call", runNextSynchronously, cancelable, threads, ns); async Task Inc() { await Task.Yield(); while (stopwatch.Elapsed < duration) { if (cancelable) { for (int i = 0; i != 64; ++i) { await mutex.LockAsync(cancel.Token); ++counter; mutex.Unlock(runNextSynchronously: runNextSynchronously); } } else { for (int i = 0; i != 64; ++i) { await mutex.LockAsync(); ++counter; mutex.Unlock(runNextSynchronously: runNextSynchronously); } } } } } } }