private void AcquireTakeCancellationHandler(object _acquireNode, bool canceling) { LinkedListNode <AsyncTake> acquireNode = (LinkedListNode <AsyncTake>)_acquireNode; AsyncTake acquire = acquireNode.Value; if (acquire.TryLock()) { // To access shared mutable state we must acquire the lock lock (theLock) { asyncTakes.Remove(acquireNode); } // Release the resources associated with the async acquire. acquire.Dispose(canceling); // Complete the TaskCompletionSource to RanToCompletion (timeout) // or Canceled final state. if (canceling) { acquire.SetCanceled(); } else { acquire.SetResult(default);
/** * 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); } } }
private void TakeCancellationHandler(object request, bool canceling) { LinkedListNode <AsyncTake> node = (LinkedListNode <AsyncTake>)request; AsyncTake take = node.Value; if (take.TryLock()) { lock (_lock) { if (node.List != null) { _asyncTakes.Remove(node); } } take.Dispose(); if (canceling) { take.SetCanceled(); } else { take.SetResult(default);
/** * Synchronous interface based on asynchronous TAP interface */ /** * Try to cancel an asynchronous take represented by its task. */ private bool CancelTakeByTask(Task <T> takeTask) { AsyncTake take = null; lock (theLock) { foreach (AsyncTake _take in asyncTakes) { if (_take.Task == takeTask) { take = _take; asyncTakes.Remove(_take); take.done = true; break; } } } if (take != null) { take.Dispose(); take.SetCanceled(); } return(take != null); }
/** * 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); }
/** * 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); }