/// <summary>
        /// Returns an awaitable that may be used to asynchronously acquire the next signal.
        /// </summary>
        /// <param name="cancellationToken">A token whose cancellation removes the caller from the queue of those waiting for the event.</param>
        /// <returns>An awaitable.</returns>
        public Task WaitAsync(CancellationToken cancellationToken)
        {
            if (cancellationToken.IsCancellationRequested)
            {
                return(ThreadingTools.TaskFromCanceled(cancellationToken));
            }

            lock (this.signalAwaiters)
            {
                if (this.signaled)
                {
                    this.signaled = false;
                    return(TplExtensions.CompletedTask);
                }
                else
                {
                    var waiter = new WaiterCompletionSource(this, cancellationToken, this.allowInliningAwaiters);
                    if (cancellationToken.IsCancellationRequested)
                    {
                        waiter.TrySetCanceled(cancellationToken);
                    }
                    else
                    {
                        this.signalAwaiters.Enqueue(waiter);
                    }

                    return(waiter.Task);
                }
            }
        }
Exemple #2
0
        /// <summary>
        /// Initializes a new instance of the <see cref="AsyncSemaphore"/> class.
        /// </summary>
        /// <param name="initialCount">The initial number of requests for the semaphore that can be granted concurrently.</param>
        public AsyncSemaphore(int initialCount)
        {
            this.semaphore           = new SemaphoreSlim(initialCount);
            this.uncontestedReleaser = Task.FromResult(new Releaser(this));

            this.canceledReleaser = ThreadingTools.TaskFromCanceled <Releaser>(new CancellationToken(canceled: true));
        }
Exemple #3
0
        /// <summary>
        /// Requests access to the lock.
        /// </summary>
        /// <param name="cancellationToken">A token whose cancellation signals lost interest in the lock.</param>
        /// <returns>A task whose result is a releaser that should be disposed to release the lock.</returns>
        public Task <Releaser> EnterAsync(CancellationToken cancellationToken = default(CancellationToken))
        {
            if (cancellationToken.IsCancellationRequested)
            {
                return(ThreadingTools.TaskFromCanceled <Releaser>(cancellationToken));
            }

            return(this.LockWaitingHelper(this.semaphore.WaitAsync(cancellationToken)));
        }
Exemple #4
0
        public Task <T> DequeueAsync(CancellationToken cancellationToken = default(CancellationToken))
        {
            if (cancellationToken.IsCancellationRequested)
            {
                return(ThreadingTools.TaskFromCanceled <T>(cancellationToken));
            }

            T result;

            lock (this.SyncRoot)
            {
                if (this.IsCompleted)
                {
                    return(TplExtensions.CanceledTaskOfT <T>());
                }

                if (this.queueElements?.Count > 0)
                {
                    result = this.queueElements.Dequeue();
                }
                else
                {
                    if (this.dequeuingWaiters == null)
                    {
                        this.dequeuingWaiters = new Queue <TaskCompletionSource <T> >(capacity: 2);
                    }
                    else
                    {
                        this.FreeCanceledDequeuers();
                    }

                    var waiterTcs = new TaskCompletionSourceWithoutInlining <T>(allowInliningContinuations: false);
                    waiterTcs.AttachCancellation(cancellationToken, this);
                    this.dequeuingWaiters.Enqueue(waiterTcs);
                    return(waiterTcs.Task);
                }
            }

            this.CompleteIfNecessary();
            return(Task.FromResult(result));
        }