//--------------------------------------------------------------------- // APM //-- public IAsyncResult BeginWaitEx(int timeout, CancellationToken ctk, AsyncCallback ucb, object ustate) { bool result = true; lock (_lock) { if (currentPermits > 0) { currentPermits -= 1; } else if (timeout == 0 || ctk.IsCancellationRequested) { result = false; } else { var waiter = new ApmWaiter <Data>(new Data(), ucb, ustate, ctk, timeout, AsyncUnlink); DListNode.AddLast(waiters, waiter); waiter.Enable(); return(waiter.AsyncResult); } } // FromResult will invoke the async callbacks, so do it outside of the lock if (result) { return(GenericAsyncResult <bool> .FromResult(ucb, ustate, true, null, true)); } // synchronous completion due to timeout or cancellation return(ctk.IsCancellationRequested ? GenericAsyncResult <bool> .FromResult(ucb, ustate, false, new OperationCanceledException(ctk), true) : GenericAsyncResult <bool> .FromResult(ucb, ustate, false, null, true)); }
public Task <bool> WaitAsyncEx(int timeout, CancellationToken ctk) { lock (_lock) { if (currentPermits > 0) { currentPermits -= 1; return(TrueTask); } // the current thread must block, so check immediate cancelers if (timeout == 0) { return(FalseTask); } ctk.ThrowIfCancellationRequested(); var waiter = new Waiter(ctk); DListNode.AddLast(waiters, waiter); // enable timeout or cancellation only after the node is in the list if (ctk.CanBeCanceled) { waiter.ctkReg = ctk.Register(OnCancellation, waiter); } if (timeout != Timeout.Infinite) { waiter.timer = new Timer(OnTimeout, waiter, timeout, Timeout.Infinite); } return(waiter.tcs.Task); } }
//--------------------------------------------------------------------- // TAP //-- public Task <bool> WaitAsyncEx(int timeout, CancellationToken ctk) { lock (_lock) { if (currentPermits > 0) { currentPermits -= 1; return(TrueTask); } // the current thread must block, so check immediate cancelers if (timeout == 0) { return(FalseTask); } ctk.ThrowIfCancellationRequested(); var waiter = new TapWaiter <Data>(new Data(), ctk, timeout, AsyncUnlink); DListNode.AddLast(waiters, waiter); waiter.Enable(); return(waiter.Task); } }
//--------------------------------------------------------------------- // Synchronous //-- public bool WaitEx(int timeout, CancellationToken ctk) { bool interrupted = false; Waiter <Data> waiter = null; bool ownsTheWaiter = false; lock (_lock) { if (currentPermits > 0) { currentPermits -= 1; return(true); } // if the current thread must block, check immediate cancelers if (timeout == 0) { return(false); } ctk.ThrowIfCancellationRequested(); // create a synchronous waiter node and insert it in the wait queue waiter = new SyncWaiter <Data>(new Data(), ctk, SyncUnlink); DListNode.AddLast(waiters, waiter); waiter.Enable(); // wrap timeout value with timeout holder, in order to support timeout adjust TimeoutHolder th = new TimeoutHolder(timeout); // wait until the request is staisfied, timeout expires or cancellation do { try { if ((timeout = th.Value) == 0) { ownsTheWaiter = TrySetStateAndRemoveWaiter(waiter, WaiterState.TIMED_OUT); break; } // wait on the monitor's condition variable MonitorEx.Wait(_lock, waiter, timeout); } catch (ThreadInterruptedException) { interrupted = true; ownsTheWaiter = TrySetStateAndRemoveWaiter(waiter, WaiterState.INTERRUPTED); break; } } while (waiter.State == WaiterState.WAITING); } // this processing is private of the current thread, so we can do it without // owning the lock. if (ownsTheWaiter) { waiter.CancelCancellation(); } if (waiter.State == WaiterState.INTERRUPTED) { throw new ThreadInterruptedException(); } if (interrupted) { Thread.CurrentThread.Interrupt(); } if (waiter.State == WaiterState.CANCELED) { throw new OperationCanceledException(ctk); } return(waiter.State == WaiterState.SUCCESS); }