Example #1
0
        /**
         * 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);
    }
Example #3
0
        /**
         * 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);
    }
Example #6
0
        /**
         * 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);
                }
            }
        }
Example #7
0
        /**
         *	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);
        }
    }
Example #9
0
        /****************************************************************************/
        public async Task <Acquire> AcquireAsync()
        {
            AsyncAcquire acquire = new AsyncAcquire(this);

            return(await acquire.Open());
        }