Ejemplo n.º 1
0
        public async Task TestReleaseThenReAcquireWithConcurrentAccess()
        {
            var sut = new FastAsyncLock();

            using (var otherThread = new AsyncTestRunner(OtherThread))
            {
                await otherThread.AdvanceTo(1);

                Assert.IsTrue(otherThread.HasLock());

                await otherThread.AdvanceTo(2);

                Assert.IsFalse(otherThread.HasLock());

                using (await sut.LockAsync(CancellationToken.None))
                {
                    await Task.Yield();

                    await otherThread.AdvanceAndFreezeBefore(3);

                    Assert.IsFalse(otherThread.HasLock());
                }

                await otherThread.AdvanceTo(4);

                Assert.IsTrue(otherThread.HasLock());
            }

            async Task OtherThread(CancellationToken ct, AsyncTestRunner r)
            {
                using (await sut.LockAsync(CancellationToken.None))
                {
                    await Task.Yield();

                    r.HasLock(true);
                    r.Sync(position: 1);
                }

                await Task.Yield();

                r.HasLock(false);
                r.Sync(position: 2);

                using (await sut.LockAsync(CancellationToken.None))
                {
                    await Task.Yield();

                    r.HasLock(true);
                    r.Sync(position: 3);
                    r.Sync(position: 4);
                }

                await Task.Yield();

                r.HasLock(false);
            }
        }
Ejemplo n.º 2
0
        public async Task TestExitFromAnotherExecutionContext()
        {
            var sut          = new FastAsyncLock();
            var locking      = default(IDisposable);
            var entryContext = default(AsyncTestContext);

            using (var externalThread = new AsyncTestRunner(ExternalThread))
            {
                entryContext = AsyncTestContext.Current;
                locking      = await sut.LockAsync(CancellationToken.None);

                await externalThread.AdvanceTo(1);

                Assert.IsTrue(externalThread.HasLock());

                await externalThread.AdvanceToEnd();
            }

            async Task ExternalThread(CancellationToken ct, AsyncTestRunner r)
            {
                Assert.AreNotEqual(entryContext, AsyncTestContext.Current);
                locking.Dispose();

                // Try to relock from the external execution context to validate that the lock was effectively released
                using (await sut.LockAsync(ct))
                {
                    r.HasLock(true);
                    r.Sync(position: 1);
                    await Task.Yield();
                }

                r.HasLock(false);
            }
        }
Ejemplo n.º 3
0
        public async Task TestConcurrentCancelFirst()
        {
            var entryContext = AsyncTestContext.Current;
            var sut          = new FastAsyncLock();
            var ct           = new CancellationTokenSource();

            using (var otherThread = new AsyncTestRunner(CommonTwoStepsLock(sut)))
            {
                // Acquire the lock on another async context
                await otherThread.Advance();

                Assert.IsTrue(otherThread.HasLock());

                // Try to acquire the lock from this async context
                entryContext.Validate();
                var locking = sut.LockAsync(CancellationToken.None);
                Assert.AreEqual(TaskStatus.WaitingForActivation, locking.Status);

                // Cancel the CT of the other thread ... this should not impact the awaiter !
                ct.Cancel();
                Assert.AreEqual(TaskStatus.WaitingForActivation, locking.Status);

                // Finally validate that if we release the lock from the other thread, we are still able to acquire the lock
                await otherThread.Advance();

                Assert.AreEqual(TaskStatus.RanToCompletion, locking.Status);
            }
        }
Ejemplo n.º 4
0
        public async Task TestConcurrentAccess()
        {
            var entryContext = AsyncTestContext.Current;
            var sut          = new FastAsyncLock();

            using (var otherThread = new AsyncTestRunner(CommonTwoStepsLock(sut)))
            {
                // Acquire the lock on another async context
                await otherThread.Advance();

                Assert.IsTrue(otherThread.HasLock());

                // Try to acquire the lock from this async context
                entryContext.Validate();
                var locking = sut.LockAsync(CancellationToken.None);
                Assert.AreEqual(TaskStatus.WaitingForActivation, locking.Status);

                await otherThread.Advance();                                 // Will release the lock

                Assert.AreEqual(TaskStatus.RanToCompletion, locking.Status); // so lock is now acquired (sync)
            }
        }
Ejemplo n.º 5
0
        public async Task TestConcurrentCancelSecond()
        {
            var entryContext = AsyncTestContext.Current;
            var sut          = new FastAsyncLock();
            var ct           = new CancellationTokenSource();

            using (var otherThread = new AsyncTestRunner(CommonTwoStepsLock(sut)))
            {
                // Acquire the lock on another async context
                await otherThread.Advance();

                Assert.IsTrue(otherThread.HasLock());

                // Try to acquire the lock from this async context
                entryContext.Validate();
                var locking = sut.LockAsync(ct.Token);
                Assert.AreEqual(TaskStatus.WaitingForActivation, locking.Status);

                // But cancel before the other async context completes
                ct.Cancel();
                Assert.AreEqual(TaskStatus.Canceled, locking.Status);
            }
        }
Ejemplo n.º 6
0
        public async Task TestConcurrentCancelSecondWithThird()
        {
            var sut = new FastAsyncLock();
            var ct  = new CancellationTokenSource();

            var thread2LockingTask = default(Task <IDisposable>);

            using (var thread1 = new AsyncTestRunner(Thread1))
                using (var thread2 = new AsyncTestRunner(Thread2))
                    using (var thread3 = new AsyncTestRunner(Thread3))
                    {
                        // Acquire the lock on thread 1 THEN
                        await thread1.AdvanceTo(1);

                        Assert.IsTrue(thread1.HasLock());

                        // Try to acquire the lock from this async context
                        await thread2.AdvanceAndFreezeBefore(1);

                        //var locking = sut.LockAsync(ct.Token);
                        Assert.AreEqual(TaskStatus.WaitingForActivation, thread2LockingTask.Status);
                        Assert.IsFalse(thread2.HasLock());

                        // Try to acquire it on thread 3
                        var t3Locked = thread3.AdvanceTo(1);
                        await thread3.IsFrozen();

                        Assert.IsFalse(thread3.HasLock());

                        // But cancel before the other async context completes
                        ct.Cancel();
                        Assert.AreEqual(TaskStatus.Canceled, thread2LockingTask.Status);

                        // Release the lock from thread1, and wait for thread 3 to acquire the lock
                        await thread1.AdvanceAndFreezeBefore(2);         // will freeze in continuation of thread 3

                        await t3Locked;

                        //Assert.IsFalse(thread1.HasLock()); // flag not set yet: the thread 1 is dead locked by the continuation of thread 3
                        Assert.IsTrue(thread3.HasLock());

                        await thread3.AdvanceToEnd();

                        //await thread1.AdvanceToEnd();
                        await Task.Delay(500);

                        Assert.IsFalse(thread1.HasLock());
                        Assert.IsFalse(thread3.HasLock());
                    }


            async Task Thread1(CancellationToken ct2, AsyncTestRunner r)
            {
                using (await sut.LockAsync(ct2))
                {
                    r.HasLock(true);
                    r.Sync(position: 1);
                }

                r.HasLock(false);
                r.Sync(position: 2);
            };

            async Task Thread2(CancellationToken ct2, AsyncTestRunner r)
            {
                thread2LockingTask = sut.LockAsync(ct.Token);
                using (await thread2LockingTask)
                {
                    r.HasLock(true);
                    r.Sync(position: 1);
                }

                r.HasLock(false);
                r.Sync(position: 2);
            }

            async Task Thread3(CancellationToken ct2, AsyncTestRunner r)
            {
                using (await sut.LockAsync(ct2))
                {
                    r.HasLock(true);
                    r.Sync(position: 1);
                }

                r.HasLock(false);
                r.Sync(position: 2);
            };
        }