/** * Auxiliary methods */ /** * Returns the list of all pending async acquires that can be satisfied with * the current number of permits owned by the semaphore. * * Note: Tis method is called when the current thread owns the lock. */ private List <AsyncAcquire> SatisfyPendingAsyncAcquires() { List <AsyncAcquire> satisfied = null; while (asyncAcquires.Count > 0) { AsyncAcquire acquire = asyncAcquires.First.Value; // Check if available permits allow satisfy this request if (acquire.acquires > permits) { break; } // Remove the request from the queue asyncAcquires.RemoveFirst(); // Try lock the request and complete it if succeeded if (acquire.TryLock()) { permits -= acquire.acquires; if (satisfied == null) { satisfied = new List <AsyncAcquire>(1); } satisfied.Add(acquire); } } return(satisfied); }
/** * Auxiliary methods */ /** * Returns the list of all pending async acquires that can be satisfied with * the number of permits currently owned by the semaphore. * * Note: This method is called when the current thread owns the lock. */ private List <AsyncAcquire> SatisfyPendingAsyncAcquires() { List <AsyncAcquire> satisfied = null; while (asyncAcquires.Count > 0) { AsyncAcquire acquire = asyncAcquires.First.Value; // Check if available permits allow satisfy this async request if (acquire.acquires > permits) { break; } // Remove the async request from the queue asyncAcquires.RemoveFirst(); // Update permits and mark acquire as done permits -= acquire.acquires; acquire.done = true; // Add the async acquire to the result list if (satisfied == null) { satisfied = new List <AsyncAcquire>(1); } satisfied.Add(acquire); } return(satisfied); }
/** * Asynchronous Task-based Asynchronous Pattern (TAP) interface. */ /** * Acquires one or more permits asynchronously enabling, optionally, * a timeout and/or cancellation. */ public Task <bool> AcquireAsync(int acquires = 1, int timeout = Timeout.Infinite, CancellationToken cToken = default(CancellationToken)) { lock (theLock) { if (asyncAcquires.Count == 0 && permits >= acquires) { permits -= acquires; return(trueTask); } // if the acquire was specified as immediate, return failure if (timeout == 0) { return(falseTask); } // If a cancellation was already requested return a task in the Canceled state if (cToken.IsCancellationRequested) { return(Task.FromCanceled <bool>(cToken)); } // Create a request node and insert it in requests queue AsyncAcquire acquire = new AsyncAcquire(acquires, cToken); LinkedListNode <AsyncAcquire> acquireNode = asyncAcquires.AddLast(acquire); /** * Activate the specified cancelers owning the lock. */ /** * Since the timeout handler, that runs on a thread pool's worker thread, * acquires the lock before access the "acquirer.timer" and "acquirer.cTokenRegistration" * these assignements will be visible to timer handler. */ if (timeout != Timeout.Infinite) { acquire.timer = new Timer(timeoutHandler, acquireNode, timeout, Timeout.Infinite); } /** * If the cancellation token is already in the canceled state, the cancellation * handler will run immediately and synchronously, which *causes no damage* because * this processing is terminal and the implicit locks can be acquired recursively. */ if (cToken.CanBeCanceled) { acquire.cTokenRegistration = cToken.Register(cancellationHandler, acquireNode); } // Return the Task<bool> that represents the async acquire return(acquire.Task); } }
/** * Try to cancel an async acquire request */ private void AcquireCancellationHandler(object _acquireNode, bool canceling) { LinkedListNode <AsyncAcquire> acquireNode = (LinkedListNode <AsyncAcquire>)_acquireNode; AsyncAcquire acquire = acquireNode.Value; bool complete = false; List <AsyncAcquire> satisfied = null; // To access shared mutable state we must acquire the lock lock (theLock) { /** * Here, the async request can be already satisfied or cancelled. */ if (!acquire.done) { // Remove the async acquire request from queue and mark it as done. asyncAcquires.Remove(acquireNode); complete = acquire.done = true; // If after removing the async acquire is possible to satisfy any // pending async acquire(s) do it if (asyncAcquires.Count > 0 && permits >= asyncAcquires.First.Value.acquires) { satisfied = SatisfyPendingAsyncAcquires(); } } } // If we cancelled the async acquire, release the resources associated with it, // and complete the underlying task. if (complete) { // Complete any satisfied async acquires if (satisfied != null) { CompleteSatisfiedAsyncAcquires(satisfied); } // Dispose the resources associated with the cancelled async acquire acquire.Dispose(canceling); // Complete the TaskCompletionSource to RanToCompletion with false (timeout) // or Canceled final state (cancellation). if (canceling) { acquire.SetCanceled(); // cancelled } else { acquire.SetResult(false); // timeout } } }
/** * Synchronous interface implemented using the asynchronous TAP interface. */ /** * Try to cancel an asynchronous acquire request identified by its task. * * Note: This method is needed to implement the synchronous interface. */ private bool TryCancelAcquireAsyncByTask(Task <bool> acquireTask) { AsyncAcquire acquire = null; List <AsyncAcquire> satisfied = null; // To access the shared mutable state we must acquire the lock lock (theLock) { foreach (AsyncAcquire _acquire in asyncAcquires) { if (_acquire.Task == acquireTask) { acquire = _acquire; asyncAcquires.Remove(_acquire); acquire.done = true; if (asyncAcquires.Count > 0 && permits >= asyncAcquires.First.Value.acquires) { satisfied = SatisfyPendingAsyncAcquires(); } break; } } } // If we canceled the async acquire, process the cancellation if (acquire != null) { // After release the lock, complete any satisfied acquires if (satisfied != null) { CompleteSatisfiedAsyncAcquires(satisfied); } // Dispose the resources associated with this async acquire and complete // its task to the Canceled state. acquire.Dispose(); acquire.SetCanceled(); return(true); } return(false); }
/** * Try to cancel an async acquire request */ private void AcquireCancellationHandler(object _acquireNode, bool canceling) { LinkedListNode <AsyncAcquire> acquireNode = (LinkedListNode <AsyncAcquire>)_acquireNode; AsyncAcquire acquire = acquireNode.Value; if (acquire.TryLock()) { List <AsyncAcquire> satisfied = null; // To access shared mutable state we must acquire the lock lock (theLock) { if (acquireNode.List != null) { asyncAcquires.Remove(acquireNode); } if (asyncAcquires.Count > 0 && permits >= asyncAcquires.First.Value.acquires) { satisfied = SatisfyPendingAsyncAcquires(); } } // Complete the satisfied async acquires CompleteSatisfiedAsyncAcquires(satisfied); // 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(false); } } }
/** * Synchronous interface implemented using the asynchronous TAP interface. */ /** * Try to cancel an asynchronous request identified by its task. * * Note: This is used to implement the synchronous interface. */ private bool CancelAcquireByTask(Task <bool> acquireTask) { AsyncAcquire acquire = null; List <AsyncAcquire> satisfied = null; // To access the shared mutable state we must acquire the lock lock (theLock) { foreach (AsyncAcquire _acquire in asyncAcquires) { if (_acquire.Task == acquireTask) { if (_acquire.TryLock()) { acquire = _acquire; asyncAcquires.Remove(_acquire); } break; } } // If the new state od semaphore allows waiting acquires, satisfy them if (asyncAcquires.Count > 0 && permits >= asyncAcquires.First.Value.acquires) { satisfied = SatisfyPendingAsyncAcquires(); } } CompleteSatisfiedAsyncAcquires(satisfied); if (acquire != null) { // Dispose the resources associated with this async acquire and complete // its task to the Canceled state. acquire.Dispose(); acquire.SetCanceled(); } return(acquire != null); }
/** * Asynchronous Task-based Asynchronous Pattern (TAP) interface. */ /** * Acquires one or more permits asynchronously enabling, optionally, * a timeout and/or cancellation. */ public Task <bool> AcquireAsync(int acquires = 1, int timeout = Timeout.Infinite, CancellationToken cToken = default(CancellationToken)) { // Validate the argument "acquires" if (acquires < 1 || acquires > maxPermits) { return(argExceptionTask); } lock (theLock) { // If the queue is empty ans sufficiente authorizations are available, // the acquire can be satisfied immediatelly; so, the field permits is // updated and a completed task is returned with a result of true. if (asyncAcquires.Count == 0 && permits >= acquires) { permits -= acquires; return(trueTask); } // If the acquire was specified as immediate, return completed task with // a result of false, which means timeout. if (timeout == 0) { return(falseTask); } // If the cancellation was already requested return a a completed task in // the Canceled state if (cToken.IsCancellationRequested) { return(Task.FromCanceled <bool>(cToken)); } // Create a request node and insert it in requests queue AsyncAcquire acquire = new AsyncAcquire(acquires, cToken); LinkedListNode <AsyncAcquire> acquireNode = asyncAcquires.AddLast(acquire); /** * Activate the specified cancelers when owning the lock. */ /** * Since the timeout handler, that runs on a thread pool's worker thread, * that acquires the lock before access the fields "acquirer.timer" and * "acquirer.cTokenRegistration" these assignements will be visible to the * timeout handler. */ if (timeout != Timeout.Infinite) { acquire.timer = new Timer(timeoutHandler, acquireNode, timeout, Timeout.Infinite); } /** * If the cancellation token is already in the canceled state, the cancellation * handler will run immediately and synchronously, which *causes no damage* because * this processing is terminal and the implicit locks can be acquired recursively. */ if (cToken.CanBeCanceled) { acquire.cTokenRegistration = cToken.Register(cancellationHandler, acquireNode); } // Return the Task<bool> that represents the async acquire return(acquire.Task); } }
/****************************************************************************/ public async Task <Acquire> AcquireAsync() { AsyncAcquire acquire = new AsyncAcquire(this); return(await acquire.Open()); }