Пример #1
0
    /**
     * Cancellation handlers
     */

    /**
     * Try to cancel an async take request.
     */
    private void TakeCancellationHandler(object _takeNode, bool canceling)
    {
        LinkedListNode <AsyncTake> takeNode = (LinkedListNode <AsyncTake>)_takeNode;
        AsyncTake take = null;

        // Acquire the lock to access the shared mutable state
        lock (theLock) {
            /**
             * Here, the async take request can be completed or canceled
             */
            if (!takeNode.Value.done)
            {
                // Remove the async take from the queue and mark it as canceled
                asyncTakes.Remove(takeNode);
                take      = takeNode.Value;
                take.done = true;
            }
        }
        if (take != null)
        {
            // Dispose resources associated with this async take request.
            take.Dispose(canceling);

            // Complete the underlying task properly.
            if (canceling)
            {
                take.SetCanceled();
            }
            else
            {
                take.SetResult(null);
            }
        }
    }
Пример #2
0
    /**
     * Put a message on the queue asynchronously enabling, optionally,
     * a timeout and/or cancellation.
     */
    public Task <bool> PutAsync(T sentMessage, int timeout = Timeout.Infinite,
                                CancellationToken cToken   = default(CancellationToken))
    {
        Task <bool> putTask = null;
        AsyncTake   take    = null;

        lock (theLock) {
            if (state != OPERATING)
            {
                throw new InvalidOperationException();
            }
            if ((putIdx - takeIdx) < capacity)
            {
                // Do an immediate put
                messageRoom[putIdx++ & mask] = sentMessage;
                putTask = trueTask;

                // Try to satisfy a pending async take request.
                if (asyncTakes.Count > 0)
                {
                    take = asyncTakes.First.Value;
                    asyncTakes.RemoveFirst();
                    take.receivedMessage = messageRoom[takeIdx++ & mask];
                    take.done            = true;
                }
            }
            else
            {
                // The current thread must block, so we check for immediate cancelers
                if (timeout == 0)
                {
                    return(falseTask);
                }

                // If a cancellation was requested return a task in the Canceled state
                if (cToken.IsCancellationRequested)
                {
                    return(Task.FromCanceled <bool>(cToken));
                }

                // Create a waiter node and insert it in the wait queue
                AsyncPut put = new AsyncPut(sentMessage, cToken);
                LinkedListNode <AsyncPut> putNode = asyncPuts.AddLast(put);

                /**
                 * Activate the specified cancelers owning the lock.
                 * Since the timeout handler acquires the lock before use the "put.timer" and
                 * "put.cTokenRegistration" the assignements will be visible.
                 */
                if (timeout != Timeout.Infinite)
                {
                    put.timer = new Timer(putTimeoutHandler, putNode, timeout, Timeout.Infinite);
                }

                /**
                 * If the cancellation token is already in the canceled state, the cancellation
                 * will run immediately and synchronously, which causes no damage because the
                 * implicit locks can be acquired recursively and this is a terminal processing.
                 */
                if (cToken.CanBeCanceled)
                {
                    put.cTokenRegistration = cToken.Register(putCancellationHandler, putNode);
                }

                // Set the result task that represents the asynchronous operation
                putTask = put.Task;
            }
        }
        // If we released any putter, cancel its cancellers and complete its tasks.
        if (take != null)
        {
            take.Dispose();
            take.SetResult(take.receivedMessage);
        }
        return(putTask);
    }