예제 #1
0
    /**
     * Try to cancel an async put request.
     */
    private void PutCancellationHandler(object _putNode, bool canceling)
    {
        LinkedListNode <AsyncPut> putNode = (LinkedListNode <AsyncPut>)_putNode;
        AsyncPut put = null;

        lock (theLock) {
            if (!putNode.Value.done)
            {
                asyncPuts.Remove(putNode);
                put      = putNode.Value;
                put.done = true;
            }
        }
        if (put != null)
        {
            // Dispose resources associated with this async put request.
            put.Dispose(canceling);

            // Complete the underlying task properly.
            if (canceling)
            {
                put.SetCanceled();
            }
            else
            {
                put.SetResult(false);
            }
        }
    }
예제 #2
0
    /**
     * Try to cancel an asynchronous put represented by its task.
     */
    private bool CancelPutByTask(Task <bool> putTask)
    {
        AsyncPut put = null;

        lock (theLock) {
            foreach (AsyncPut _put in asyncPuts)
            {
                if (_put.Task == putTask)
                {
                    put = _put;
                    asyncPuts.Remove(_put);
                    break;
                }
            }
        }
        if (put != null)
        {
            put.Dispose();
            put.SetCanceled();
        }
        return(put != null);
    }
예제 #3
0
    /**
     * Asynchronous TAP interface
     */

    /**
     * Take a message from the queue asynchronously enabling, optionally,
     * timeout and/or cancellation.
     */
    public Task <T> TakeAsync(int timeout = Timeout.Infinite,
                              CancellationToken cToken = default(CancellationToken))
    {
        Task <T> takeTask = null;
        AsyncPut put      = null;

        lock (theLock) {
            if (putIdx - takeIdx > 0)
            {
                // Immediate take
                takeTask = Task.FromResult <T>(messageRoom[takeIdx++ & mask]);

                // Try to satisfy a pending async put request
                if (asyncPuts.Count > 0)
                {
                    put = asyncPuts.First.Value;
                    asyncPuts.RemoveFirst();
                    messageRoom[putIdx++ & mask] = put.sentMessage;
                    put.done = true;
                }

                /**
                 * If the queue is in the COMPLETING state, the message queue is empty and
                 * we released the last pending put, then transition the queue to the
                 * COMPLETED state.
                 */
                if (putIdx == takeIdx && state == COMPLETING && asyncPuts.Count == 0)
                {
                    state = COMPLETED;
                }
            }
            else
            {
                // If the queue was already completed or an immediate take was spedified
                // return failure.
                if (state != OPERATING)
                {
                    throw new InvalidOperationException();
                }
                if (timeout == 0)
                {
                    return(nullTask);
                }

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

                // Create a waiter node and insert it in the wait queue
                AsyncTake take = new AsyncTake(cToken);
                LinkedListNode <AsyncTake> takeNode = asyncTakes.AddLast(take);

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

                /**
                 * If the cancellation token is already in the cancelled 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)
                {
                    take.cTokenRegistration = cToken.Register(takeCancellationHandler, takeNode);
                }

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