Example #1
0
        /// <summary>
        /// Try to skip to the head of the queue.
        /// </summary>
        /// <param name="AHandle">
        /// The output <see cref="SynchronizationHandle"/> for the skipped turn.
        /// </param>
        /// <returns>
        /// <see langword="true"/> if skipping was successful and <paramref name="AHandle"/> is
        /// live; otherwise <see langword="false"/>.
        /// </returns>
        /// <remarks>
        /// <para>
        /// Skipping means entering an empty queue to immediately start a turn. Internally, the
        /// caller enters the queue regardless of state but cancels any wait immediately, reporting
        /// failure instead.
        /// </para>
        /// <para>
        /// When the result is <see langword="true"/>, <paramref name="AHandle"/> is acquired and
        /// live and must be disposed!
        /// </para>
        /// </remarks>
        public bool TrySkip(out SynchronizationHandle AHandle)
        {
            AHandle = null;

            if (IsDisposed)
            {
                // Cannot skip a disposed queue.
                return(false);
            }

            // Make a handle to end this turn.
            var handle = new Handle();
            // Update the tail to reserve our position whilst getting our immediate predecessor.
            // NOTE: Exception cannot be thrown.
            // ReSharper disable once ExceptionNotDocumented
            var predecessor = Interlocked.Exchange(ref FTail, handle);

            if (predecessor.IsReleased)
            {
                // Successfully skipped to the head of the queue.
                AHandle = handle;
                return(true);
            }

            // Immediately bypass to cede our turn.
#pragma warning disable 4014
            predecessor.Turn.WaitAsync()
            .ContinueWith(
                A =>
            {
                if (A.IsFaulted)
                {
                    handle.Fault();
                }
                else
                {
                    handle.Dispose();
                }
            },
                TaskContinuationOptions.ExecuteSynchronously
                );
#pragma warning restore 4014
            return(false);
        }
Example #2
0
        /// <inheritdoc />
        /// <exception cref="OperationCanceledException">
        /// <paramref name="ACancel"/> was canceled.
        /// </exception>
        /// <exception cref="ObjectDisposedException">This instance is disposed.</exception>
        public async Task <SynchronizationHandle> WaitAsync(CancellationToken ACancel)
        {
            ThrowIfDisposed();
            ACancel.ThrowIfCancellationRequested();

            var id = TaskContext.CurrentId;

            // Strengthen the lock to prevent release (temporarily).
            Strengthen();

            if (FOwner == id)
            {
                // Re-enter the lock.
                return(new Handle(this));
            }

            // The lock is either unacquired or acquired by some other context.
            Task <SynchronizationHandle> turn;

            try
            {
                // Acquire an awaitable to await our turn.
                turn = FQueue.WaitAsync(ACancel);
            }
            finally
            {
                // Weak the lock to allow release again.
                Weaken();
            }

            // Await our turn.
            FHead = await turn;

            // We now have exclusive access.
            FOwner = id;
            Strengthen();
            return(new Handle(this));
        }