public void AsyncLock_Locked_PreventsLockUntilUnlocked()
        {
            AsyncContext.Run(async () =>
            {
                var mutex = new AsyncLock();
                var task1HasLock = new TaskCompletionSource();
                var task1Continue = new TaskCompletionSource();

                Task<IDisposable> task1LockTask = null;
                var task1 = Task.Run(async () =>
                {
                    task1LockTask = mutex.LockAsync();
                    using (await task1LockTask)
                    {
                        task1HasLock.SetResult();
                        await task1Continue.Task;
                    }
                });
                await task1HasLock.Task;

                Task<IDisposable> task2LockTask = null;
                var task2Start = Task.Factory.StartNew(async () =>
                {
                    task2LockTask = mutex.LockAsync();
                    await task2LockTask;
                });
                var task2 = await task2Start;

                Assert.IsFalse(task2.IsCompleted);
                task1Continue.SetResult();
                await task2;
            });
        }
        public void AsyncLock_Locked_PreventsLockUntilUnlocked()
        {
            Test.Async(async () =>
            {
                var mutex = new AsyncLock();
                var task1HasLock = new TaskCompletionSource();
                var task1Continue = new TaskCompletionSource();

                var task1 = TaskShim.Run(async () =>
                {
                    using (await mutex.LockAsync())
                    {
                        task1HasLock.SetResult();
                        await task1Continue.Task;
                    }
                });
                await task1HasLock.Task;

                var task2Start = Task.Factory.StartNew(async () =>
                {
                    await mutex.LockAsync();
                });
                var task2 = await task2Start;

                Assert.IsFalse(task2.IsCompleted);
                task1Continue.SetResult();
                await task2;
            });
        }
        public void Locked_PreventsLockUntilUnlocked()
        {
            AsyncContext.Run(async () =>
            {
                var monitor = new AsyncMonitor();
                var task1HasLock = new TaskCompletionSource();
                var task1Continue = new TaskCompletionSource();
                Task<IDisposable> initialLockTask = null;

                var task1 = Task.Run(async () =>
                {
                    initialLockTask = monitor.EnterAsync();
                    using (await initialLockTask)
                    {
                        task1HasLock.SetResult();
                        await task1Continue.Task;
                    }
                });
                await task1HasLock.Task;

                var lockTask = monitor.EnterAsync();
                Assert.IsFalse(lockTask.IsCompleted);
                task1Continue.SetResult();
                await lockTask;
            });
        }
        public void ProgressReport_NotifiesChangeOnCapturedSynchronizationContext()
        {
            Test.Async(async () =>
            {
                SynchronizationContext updateContext = null;
                SynchronizationContext threadContext = null;

                var tcs = new TaskCompletionSource();
                using (var thread = new AsyncContextThread())
                {
                    threadContext = await thread.Factory.Run(() => SynchronizationContext.Current);
                    PropertyProgress<int> propertyProgress = await thread.Factory.Run(() => new PropertyProgress<int>());
                    propertyProgress.PropertyChanged += (_, e) =>
                    {
                        updateContext = SynchronizationContext.Current;
                        tcs.SetResult();
                    };
                    IProgress<int> progress = propertyProgress;
                    progress.Report(13);
                    await tcs.Task;
                }

                Assert.IsNotNull(updateContext);
                Assert.AreEqual(threadContext, updateContext);
            });
        }
Exemple #5
0
 /// <summary>
 ///     Creates an async-compatible manual-reset event.
 /// </summary>
 /// <param name="set">Whether the manual-reset event is initially set or unset.</param>
 public AsyncManualResetEvent(bool set) {
     _sync = new object();
     _tcs = new TaskCompletionSource();
     if (set) {
         //Enlightenment.Trace.AsyncManualResetEvent_Set(this, _tcs.Task);
         _tcs.SetResult();
     }
 }
Exemple #6
0
		private static Task<string> GetSomeTextAsync()
		{
			// https://msdn.microsoft.com/en-us/library/hh873177(v=vs.110).aspx
			var tcs = new TaskCompletionSource<string>();
			tcs.SetResult("some text");

			return tcs.Task;
		}
 public void SignalAndWaitAsync_Underflow_ThrowsException()
 {
     var tcs = new TaskCompletionSource();
     var barrier = new AsyncBarrier(1, async _ => { await tcs.Task; });
     barrier.SignalAndWaitAsync();
     AssertEx.ThrowsException<InvalidOperationException>(() => barrier.SignalAndWaitAsync());
     tcs.SetResult();
 }
        private Task SynchronouslyEndingOperation()
        {
            Synchronous.Log("Entered synchronously ending operation");
            Thread.Sleep(100);
            var tcs = new TaskCompletionSource();            
            tcs.SetResult();
            Synchronous.Log("Leaving synchronously ending operation");
            return tcs.Task;

        }
        public void FromTaskSynchronously_TaskCompletes_TokenGetsCancellationRequested()
        {
            var tcs = new TaskCompletionSource();
            var result = CancellationTokenHelpers.FromTask(tcs.Task, TaskContinuationOptions.ExecuteSynchronously);

            tcs.SetResult();

            Assert.IsTrue(result.Token.CanBeCanceled);
            Assert.IsTrue(result.Token.IsCancellationRequested);
        }
        public void Pulse_ReleasesOneWaiter()
        {
            AsyncContext.Run(async () =>
            {
                var monitor = new AsyncMonitor();
                int completed = 0;
                var task1Ready = new TaskCompletionSource();
                var task2Ready = new TaskCompletionSource();
                Task<IDisposable> lockTask1 = null;
                Task waitTask1 = null;
                var task1 = Task.Run(async () =>
                {
                    lockTask1 = monitor.EnterAsync();
                    using (await lockTask1)
                    {
                        waitTask1 = monitor.WaitAsync();
                        task1Ready.SetResult();
                        await waitTask1;
                        Interlocked.Increment(ref completed);
                    }
                });
                await task1Ready.Task;
                Task<IDisposable> lockTask2 = null;
                Task waitTask2 = null;
                var task2 = Task.Run(async () =>
                {
                    lockTask2 = monitor.EnterAsync();
                    using (await lockTask2)
                    {
                        waitTask2 = monitor.WaitAsync();
                        task2Ready.SetResult();
                        await waitTask2;
                        Interlocked.Increment(ref completed);
                    }
                });
                await task2Ready.Task;

                Task<IDisposable> lockTask3 = monitor.EnterAsync();
                using (await lockTask3)
                {
                    monitor.Pulse();
                }
                await Task.WhenAny(task1, task2);
                var result = Interlocked.CompareExchange(ref completed, 0, 0);

                Assert.AreEqual(1, result);
            });
        }
        public void AsyncLazy_Start_CallsFunc()
        {
            AsyncContext.Run(async () =>
            {
                var tcs = new TaskCompletionSource();
                Func<int> func = () =>
                {
                    tcs.SetResult();
                    return 13;
                };
                var lazy = new AsyncLazy<int>(func);

                lazy.Start();
                await tcs.Task;
            });
        }
        public void AsyncLock_DoubleDispose_OnlyPermitsOneTask()
        {
            AsyncContext.Run(async () =>
            {
                var mutex = new AsyncLock();
                var task1HasLock = new TaskCompletionSource();
                var task1Continue = new TaskCompletionSource();

                Task<IDisposable> lockTask = null;
                await Task.Run(async () =>
                {
                    lockTask = mutex.LockAsync();
                    var key = await lockTask;
                    key.Dispose();
                    key.Dispose();
                });

                Task<IDisposable> task1LockTask = null;
                var task1 = Task.Run(async () =>
                {
                    task1LockTask = mutex.LockAsync();
                    using (await task1LockTask)
                    {
                        task1HasLock.SetResult();
                        await task1Continue.Task;
                    }
                });
                await task1HasLock.Task;

                Task<IDisposable> task2LockTask = null;
                var task2Start = Task.Factory.StartNew(async () =>
                {
                    task2LockTask = mutex.LockAsync();
                    await task2LockTask;
                });
                var task2 = await task2Start;

                Assert.IsFalse(task2.IsCompleted);
                task1Continue.SetResult();
                await task2;
            });
        }
        public void Pulse_ReleasesOneWaiter()
        {
            Test.Async(async () =>
            {
                var monitor = new AsyncMonitor();
                int completed = 0;
                var task1Ready = new TaskCompletionSource();
                var task2Ready = new TaskCompletionSource();
                var task1 = TaskShim.Run(async () =>
                {
                    using (await monitor.EnterAsync())
                    {
                        var waitTask1 = monitor.WaitAsync();
                        task1Ready.SetResult();
                        await waitTask1;
                        Interlocked.Increment(ref completed);
                    }
                });
                await task1Ready.Task;
                var task2 = TaskShim.Run(async () =>
                {
                    using (await monitor.EnterAsync())
                    {
                        var waitTask2 = monitor.WaitAsync();
                        task2Ready.SetResult();
                        await waitTask2;
                        Interlocked.Increment(ref completed);
                    }
                });
                await task2Ready.Task;

                using (await monitor.EnterAsync())
                {
                    monitor.Pulse();
                }
                await TaskShim.WhenAny(task1, task2);
                var result = Interlocked.CompareExchange(ref completed, 0, 0);

                Assert.AreEqual(1, result);
            });
        }
 public void WriteLocked_Unlocked_PermitsAnotherWriterLock()
 {
     AsyncContext.Run(async () =>
     {
         var rwl = new AsyncReaderWriterLock();
         var firstWriteLockTaken = new TaskCompletionSource();
         var releaseFirstWriteLock = new TaskCompletionSource();
         var task = Task.Run(async () =>
         {
             using (await rwl.WriterLockAsync())
             {
                 firstWriteLockTaken.SetResult();
                 await releaseFirstWriteLock.Task;
             }
         });
         await firstWriteLockTaken.Task;
         var lockTask = rwl.WriterLockAsync();
         Assert.IsFalse(lockTask.IsCompleted);
         releaseFirstWriteLock.SetResult();
         await lockTask;
     });
 }
        public void Locked_PreventsLockUntilUnlocked()
        {
            Test.Async(async () =>
            {
                var monitor = new AsyncMonitor();
                var task1HasLock = new TaskCompletionSource();
                var task1Continue = new TaskCompletionSource();

                var task1 = TaskShim.Run(async () =>
                {
                    using (await monitor.EnterAsync())
                    {
                        task1HasLock.SetResult();
                        await task1Continue.Task;
                    }
                });
                await task1HasLock.Task;

                var lockTask = monitor.EnterAsync().AsTask();
                Assert.IsFalse(lockTask.IsCompleted);
                task1Continue.SetResult();
                await lockTask;
            });
        }
        /*

        Old                     New                                 Description
        
        task.Wait	            await task	                        Wait/await for a task to complete
        
        task.Result	            await task	                        Get the result of a completed task
        
        Task.WaitAny	        await Task.WhenAny	                Wait/await for one of a collection of tasks to complete
        
        Task.WaitAll	        await Task.WhenAll	                Wait/await for every one of a collection of tasks to complete
        
        Thread.Sleep	        await Task.Delay	                Wait/await for a period of time
        
        Task constructor	    Task.Run or TaskFactory.StartNew	Create a code-based task

        */

        #endregion

        #region Mapping

        /*
            
        Type                                    Lambda                                                  Parameters	    Return Value
            
        Action	                                () => { }	                                            None	        None
        Func<Task>	                            async () => { await Task.Yield(); }	                    None	        None
            
        Func<TResult>	                        () => { return 6; }	                                    None	        TResult
        Func<Task<TResult>>	                    async () => { await Task.Yield(); return 6; }	        None	        TResult
            
        Action<TArg1>	                        x => { }	                                            TArg1	        None
        Func<TArg1, Task>	                    async x => { await Task.Yield(); }	                    TArg1	        None
            
        Func<TArg1, TResult>	                x => { return 6; }	                                    TArg1	        TResult
        Func<TArg1, Task<TResult>>	            async x => { await Task.Yield(); return 6; }	        TArg1	        TResult
            
        Action<TArg1, TArg2>	                (x, y) => { }	                                        TArg1, TArg2	None
        Func<TArg1, TArg2, Task>	            async (x, y) => { await Task.Yield(); }	                TArg1, TArg2	None
            
        Func<TArg1, TArg2, TResult>	            (x, y) => { return 6; }	                                TArg1, TArg2	TResult
        Func<TArg1, TArg2, Task<TResult>>	    async (x, y) => { await Task.Yield(); return 6; }	    TArg1, TArg2	TResult

        */

        #endregion

        #region DelayImplementation

        private static Task Delay(int milliseconds)
        {
            TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();

            Timer timer = new Timer(x => tcs.SetResult(null), null, milliseconds, Timeout.Infinite);

            tcs.Task.ContinueWith(x => timer.Dispose());

            return tcs.Task;
        }
 public void UpgradeableReadAndReadLocked_Upgrade_WaitsForReaderLockToUnlock()
 {
     Test.Async(async () =>
     {
         var rwl = new AsyncReaderWriterLock();
         var readLockTaken = new TaskCompletionSource();
         var releaseReadLock = new TaskCompletionSource();
         var task = TaskShim.Run(async () =>
         {
             using (await rwl.ReaderLockAsync())
             {
                 readLockTaken.SetResult();
                 await releaseReadLock.Task;
             }
         });
         await readLockTaken.Task;
         using (var key = await rwl.UpgradeableReaderLockAsync())
         {
             Assert.IsFalse(key.Upgraded);
             var lockTask = key.UpgradeAsync().AsTask();
             Assert.IsFalse(lockTask.IsCompleted);
             releaseReadLock.SetResult();
             await lockTask;
             Assert.IsTrue(key.Upgraded);
         }
     });
 }
        public void UpgradeableReadAndReadLocked_UpgradeAborted_CompletesAsCanceled()
        {
            Test.Async(async () =>
            {
                var rwl = new AsyncReaderWriterLock();
                var readLockTaken = new TaskCompletionSource();
                var task = TaskShim.Run(async () =>
                {
                    using (await rwl.ReaderLockAsync())
                    {
                        readLockTaken.SetResult();
                        await TaskConstants.Never;
                    }
                });
                await readLockTaken.Task;
                Task upgradeTask;
                using (var key = await rwl.UpgradeableReaderLockAsync())
                {
                    upgradeTask = key.UpgradeAsync().AsTask();
                    Assert.IsFalse(key.Upgraded);
                }

                await AssertEx.ThrowsExceptionAsync<OperationCanceledException>(upgradeTask);
            });
        }
 public void SetResult_CompletesTask()
 {
     Test.Async(async () =>
     {
         var tcs = new TaskCompletionSource();
         tcs.SetResult();
         await tcs.Task;
     });
 }
 public void SetResult_CompletesTask()
 {
     AsyncContext.Run(async () =>
     {
         var tcs = new TaskCompletionSource();
         tcs.SetResult();
         await tcs.Task;
     });
 }
        public void AsyncLock_Locked_OnlyPermitsOneLockerAtATime()
        {
            Test.Async(async () =>
            {
                var mutex = new AsyncLock();
                var task1HasLock = new TaskCompletionSource();
                var task1Continue = new TaskCompletionSource();
                var task2HasLock = new TaskCompletionSource();
                var task2Continue = new TaskCompletionSource();

                var task1 = TaskShim.Run(async () =>
                {
                    using (await mutex.LockAsync())
                    {
                        task1HasLock.SetResult();
                        await task1Continue.Task;
                    }
                });
                await task1HasLock.Task;

                var task2Start = Task.Factory.StartNew(async () =>
                {
                    using (await mutex.LockAsync())
                    {
                        task2HasLock.SetResult();
                        await task2Continue.Task;
                    }
                });
                var task2 = await task2Start;

                var task3Start = Task.Factory.StartNew(async () =>
                {
                    await mutex.LockAsync();
                });
                var task3 = await task3Start;

                task1Continue.SetResult();
                await task2HasLock.Task;

                Assert.IsFalse(task3.IsCompleted);
                task2Continue.SetResult();
                await task2;
                await task3;
            });
        }
        public void TestAsync()
        {
            const int taskCount = 5000;
            
            // Create an asynchronous context in which to run.
            AsyncContext.Run(
                async ()
                =>
                          {
                              Task[] tasks = new Task[taskCount];
                              for (int a = 0; a < taskCount; a++)
                                  tasks[a] = TaskEx.RunEx(
                                      async () =>
                                                {
                                                    ContextStack<string> stack = new ContextStack<string>();
                                                    TaskCompletionSource tcs1 = new TaskCompletionSource();
                                                    TaskCompletionSource tcs2 = new TaskCompletionSource();
                                                    TaskCompletionSource tcs3 = new TaskCompletionSource();

                                                    string randomString = Guid.NewGuid().ToString();
                                                    string randomString2 = Guid.NewGuid().ToString();
                                                    using (stack.Region(randomString))
                                                    {
                                                        // Check we have 'A' in the current stack.
                                                        Assert.AreEqual(randomString, stack.Current);
                                                        Assert.AreEqual(1, stack.CurrentStack.Count());
                                                        Assert.AreEqual(randomString, stack.CurrentStack.Last());
                                                        int threadId = Thread.CurrentThread.ManagedThreadId;

                                                        // Await the task
                                                        await TaskEx.Delay(500);

                                                        // Check we still have 'A' in the current stack.
                                                        Assert.AreEqual(randomString, stack.Current);
                                                        Assert.AreEqual(1, stack.CurrentStack.Count());
                                                        Assert.AreEqual(randomString, stack.CurrentStack.Last());


                                                        // Create new thread.
                                                        Task task = TaskEx.RunEx(
                                                            async () =>
                                                                      {
                                                                          int task2Thread = Thread.CurrentThread.ManagedThreadId;

                                                                          // Assess if this is a new thread
                                                                          if (threadId != task2Thread)
                                                                              Interlocked.Increment(ref _task2NewThread);

                                                                          // Check we have 'A' in the current stack.
                                                                          Assert.AreEqual(randomString,
                                                                                          stack.Current);
                                                                          Assert.AreEqual(1, stack.CurrentStack.Count());
                                                                          Assert.AreEqual(randomString,
                                                                                          stack.CurrentStack.Last());

                                                                          // Wait for the first signal
                                                                          await tcs1.Task;

                                                                          // Check we still have 'A' in the current stack (i.e. we're not affected by additions in first thread.
                                                                          Assert.AreEqual(randomString, stack.Current);
                                                                          Assert.AreEqual(1, stack.CurrentStack.Count());
                                                                          Assert.AreEqual(randomString,
                                                                                          stack.CurrentStack.Last());

                                                                          // Add C to stack.
                                                                          using (stack.Region("C"))
                                                                          {
                                                                              // We should have A, C in stack now.
                                                                              Assert.AreEqual("C", stack.Current);
                                                                              Assert.AreEqual(2,
                                                                                              stack.CurrentStack.Count());
                                                                              Assert.AreEqual(randomString,
                                                                                              stack.CurrentStack.First());

                                                                              // Second signal
                                                                              tcs2.SetResult();

                                                                              // Wait for the 3rd signal
                                                                              await tcs3.Task;

                                                                              // We should still have A, C in stack now.
                                                                              Assert.AreEqual("C", stack.Current);
                                                                              Assert.AreEqual(2,
                                                                                              stack.CurrentStack.Count());
                                                                              Assert.AreEqual(randomString,
                                                                                              stack.CurrentStack.First());
                                                                          }

                                                                          // Back to just having C.
                                                                          Assert.AreEqual(randomString, stack.Current);
                                                                          Assert.AreEqual(1, stack.CurrentStack.Count());
                                                                          Assert.AreEqual(randomString,
                                                                                          stack.CurrentStack.Last());

                                                                          // Wait a bit before finishing.
                                                                          await TaskEx.Delay(100);


                                                                          if (task2Thread !=
                                                                              Thread.CurrentThread.ManagedThreadId)
                                                                              Interlocked.Increment(
                                                                                  ref _task2ThreadSwitch);
                                                                      });


                                                        // Add B to stack.
                                                        using (stack.Region(randomString2))
                                                        {
                                                            // We should have A, B in stack now.
                                                            Assert.AreEqual(randomString2, stack.Current);
                                                            Assert.AreEqual(2, stack.CurrentStack.Count());
                                                            Assert.AreEqual(randomString, stack.CurrentStack.First());

                                                            // Signal 2nd task with first signal.
                                                            tcs1.SetResult();

                                                            // Wait for 2nd task to signal back with 2nd second.
                                                            await tcs2.Task;

                                                            // We should still have A, B in stack now.
                                                            Assert.AreEqual(randomString2, stack.Current);
                                                            Assert.AreEqual(2, stack.CurrentStack.Count());
                                                            Assert.AreEqual(randomString, stack.CurrentStack.First());

                                                            // Signal 2nd task with third signal
                                                            tcs3.SetResult();

                                                            // Wait for task to finish.
                                                            await task;

                                                            // We should still have A, B in stack now.
                                                            Assert.AreEqual(randomString2, stack.Current);
                                                            Assert.AreEqual(2, stack.CurrentStack.Count());
                                                            Assert.AreEqual(randomString, stack.CurrentStack.First());
                                                        }

                                                        // We should just have A in stack.
                                                        Assert.AreEqual(randomString, stack.Current);
                                                        Assert.AreEqual(1, stack.CurrentStack.Count());

                                                        if (threadId != Thread.CurrentThread.ManagedThreadId)
                                                            Interlocked.Increment(ref _task1ThreadSwitch);
                                                    }

                                                    // The stack should be empty
                                                    Assert.IsNull(stack.Current);
                                                    Assert.AreEqual(0, stack.CurrentStack.Count());
                                                });

                              await TaskEx.WhenAll(tasks);
                          });

            Trace.WriteLine(
                String.Format(
                    "Task1 Thread Switch: {1}{0}Task2 Thread Switch: {2}{0}Task2 new thread: {3}{0}Total tasks: {4}",
                    Environment.NewLine,
                    _task1ThreadSwitch,
                    _task2ThreadSwitch,
                    _task2NewThread,
                    taskCount));
        }
        public void AsyncLock_DoubleDispose_OnlyPermitsOneTask()
        {
            Test.Async(async () =>
            {
                var mutex = new AsyncLock();
                var task1HasLock = new TaskCompletionSource();
                var task1Continue = new TaskCompletionSource();

                await TaskShim.Run(async () =>
                {
                    var key = await mutex.LockAsync();
                    key.Dispose();
                    key.Dispose();
                });

                var task1 = TaskShim.Run(async () =>
                {
                    using (await mutex.LockAsync())
                    {
                        task1HasLock.SetResult();
                        await task1Continue.Task;
                    }
                });
                await task1HasLock.Task;

                var task2Start = Task.Factory.StartNew(async () =>
                {
                    await mutex.LockAsync();
                });
                var task2 = await task2Start;

                Assert.IsFalse(task2.IsCompleted);
                task1Continue.SetResult();
                await task2;
            });
        }
        public void AsyncLock_Locked_OnlyPermitsOneLockerAtATime()
        {
            AsyncContext.Run(async () =>
            {
                var mutex = new AsyncLock();
                var task1HasLock = new TaskCompletionSource();
                var task1Continue = new TaskCompletionSource();
                var task2HasLock = new TaskCompletionSource();
                var task2Continue = new TaskCompletionSource();
                Task<IDisposable> task1LockTask = null, task2LockTask = null, task3LockTask = null;

                var task1 = Task.Run(async () =>
                {
                    task1LockTask = mutex.LockAsync();
                    using (await task1LockTask)
                    {
                        task1HasLock.SetResult();
                        await task1Continue.Task;
                    }
                });
                await task1HasLock.Task;

                var task2Start = Task.Factory.StartNew(async () =>
                {
                    task2LockTask = mutex.LockAsync();
                    using (await task2LockTask)
                    {
                        task2HasLock.SetResult();
                        await task2Continue.Task;
                    }
                });
                var task2 = await task2Start;

                var task3Start = Task.Factory.StartNew(async () =>
                {
                    task3LockTask = mutex.LockAsync();
                    await task3LockTask;
                });
                var task3 = await task3Start;

                task1Continue.SetResult();
                await task2HasLock.Task;

                Assert.IsFalse(task3.IsCompleted);
                task2Continue.SetResult();
                await task2;
                await task3;
            });
        }
        public void AsyncLock_CancelledLock_LeavesLockUnlocked()
        {
            AsyncContext.Run(async () =>
            {
                var mutex = new AsyncLock();
                var cts = new CancellationTokenSource();
                var taskReady = new TaskCompletionSource();
                Task<IDisposable> initialLockTask = null, lockTask = null;

                initialLockTask = mutex.LockAsync();
                var unlock = await initialLockTask;
                var task = Task.Run(async () =>
                {
                    lockTask = mutex.LockAsync(cts.Token);
                    taskReady.SetResult();
                    await lockTask;
                });
                await taskReady.Task;
                cts.Cancel();
                await AssertEx.ThrowsExceptionAsync<OperationCanceledException>(task);
                Assert.IsTrue(task.IsCanceled);
                unlock.Dispose();

                var finalLockTask = mutex.LockAsync();
                await finalLockTask;
            });
        }
        /// <summary>
        /// Invoked when the browser is disconnected.
        /// </summary>
        /// <param name="tcs"></param>
        /// <param name="args"></param>
        void OnDisconnected(TaskCompletionSource<VoiceXmlResult> tcs, DisconnectedEventArgs args)
        {
            Dispatch(() =>
            {
                if (tcs.Task.IsCompleted)
                    return;

                tcs.SetResult(null);
            });
        }
        public void AsyncLazy_MultipleAwaiters_OnlyInvokeAsyncFuncOnce()
        {
            AsyncContext.Run(async () =>
            {
                int invokeCount = 0;
                var tcs = new TaskCompletionSource();
                Func<Task<int>> func = async () =>
                {
                    Interlocked.Increment(ref invokeCount);
                    await tcs.Task;
                    return 13;
                };
                var lazy = new AsyncLazy<int>(func);

                var task1 = Task.Factory.StartNew(async () => await lazy).Result;
                var task2 = Task.Factory.StartNew(async () => await lazy).Result;

                Assert.IsFalse(task1.IsCompleted);
                Assert.IsFalse(task2.IsCompleted);
                tcs.SetResult();
                var results = await Task.WhenAll(task1, task2);
                Assert.IsTrue(results.SequenceEqual(new[] { 13, 13 }));
                Assert.AreEqual(1, invokeCount);
            });
        }
        public async Task RecursiveAsyncLock_DoesNotPermitIndependentWaits()
        {
            var mutex0 = new RecursiveAsyncLock();
            using (await mutex0.LockAsync())
            {
                var mutex = new RecursiveAsyncLock();
                Func<TaskCompletionSource, TaskCompletionSource, Task> taker = async (ready, finish) =>
                {
                    Assert.IsFalse(AsyncLockTracker.Contains(mutex));
                    using (await mutex.LockAsync())
                    {
                        Assert.IsTrue(AsyncLockTracker.Contains(mutex));
                        ready.TrySetResult();
                        await finish.Task;
                        Assert.IsTrue(AsyncLockTracker.Contains(mutex));
                    }
                    Assert.IsFalse(AsyncLockTracker.Contains(mutex));
                };

                var ready1 = new TaskCompletionSource();
                var finish1 = new TaskCompletionSource();
                Assert.IsFalse(AsyncLockTracker.Contains(mutex));
                var task1 = taker(ready1, finish1);
                Assert.IsFalse(AsyncLockTracker.Contains(mutex));
                await Task.WhenAny(ready1.Task, task1);
                Assert.IsFalse(AsyncLockTracker.Contains(mutex));

                var ready2 = new TaskCompletionSource();
                var finish2 = new TaskCompletionSource();
                Assert.IsFalse(AsyncLockTracker.Contains(mutex));
                var task2 = taker(ready2, finish2);
                Assert.IsFalse(AsyncLockTracker.Contains(mutex));

                Assert.IsFalse(ready2.Task.Wait(1000));

                finish1.SetResult();
                await Task.WhenAny(ready2.Task, task2);
                Assert.IsFalse(AsyncLockTracker.Contains(mutex));
                finish2.SetResult();
                await Task.WhenAll(task1, task2);
                Assert.IsFalse(AsyncLockTracker.Contains(mutex));
            }
        }
        /// <summary>
        /// Invoked when the session is complete. Sets the results of the session on the given task source.
        /// </summary>
        /// <param name="tcs"></param>
        /// <param name="args"></param>
        void OnSessionCompleted(TaskCompletionSource<VoiceXmlResult> tcs, SessionCompletedEventArgs args)
        {
            if (tcs.Task.IsCompleted)
                return;

            Dispatch(() =>
            {
                if (tcs.Task.IsCompleted)
                    return;

                if (args.Cancelled)
                    tcs.SetCanceled();
                else if (args.Error != null)
                    tcs.SetException(args.Error);
                else if (args.Result.UnhandledThrowElement != null)
                    tcs.SetException(new UnhandledPageThrowException(args.Result.UnhandledThrowElement));
                else
                    tcs.SetResult(args.Result);
            });
        }