示例#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
    /**
     * 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);
    }
示例#4
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);
    }