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); } }
private void AsyncUnlink(DListNode waiter) { lock (_lock) { DListNode.RemoveIfInserted(waiter); } }
//--------------------------------------------------------------------- // 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 void AddNode(DListNode node) { node.Pre = tail.Pre; node.Next = tail; tail.Pre.Next = node; tail.Pre = node; }
private void SyncUnlink(DListNode waiter) { lock (_lock) { DListNode.RemoveIfInserted(waiter); MonitorEx.PulseAll(_lock, waiter); } }
// Inserts the specified entry at the tail of the list. public static void AddLast(DListNode list, DListNode entry) { DListNode prev = list.prev; entry.next = list; entry.prev = prev; prev.next = entry; list.prev = entry; }
// Removes the entry that is at the tail of the list. public static DListNode RemoveLast(DListNode list) { DListNode entry = list.prev, prev = entry.prev; list.prev = prev; prev.next = list; entry.next = entry.prev = null; // mark as removed and help GC! return(entry); }
// Removes the entry that is at the front of the list. public static DListNode RemoveFirst(DListNode list) { DListNode entry = list.next, next = entry.next; list.next = next; next.prev = list; entry.next = entry.prev = null; // mark as removed! return(entry); }
// Removes the specified entry from the list that contains it. public static bool Remove(DListNode entry) { DListNode next = entry.next, prev = entry.prev; next.prev = prev; prev.next = next; entry.next = entry.prev = null; // mark as removed! return(next == prev); }
// Inserts the specified entry at the head of the list. public static void AddFirst(DListNode list, DListNode entry) { DListNode next = list.next; entry.next = next; entry.prev = list; next.prev = entry; list.next = entry; }
private bool TrySetStateAndRemoveWaiter(Waiter <Data> waiter, int state) { bool res = waiter.TrySetState(state); if (res) { DListNode.RemoveIfInserted(waiter); } return(res); }
public LRUCache(int capacity) { _lruValDic = new Dictionary <int, DListNode>(capacity); _size = capacity; head = new DListNode(-1, -1); tail = new DListNode(-1, -1); head.Next = tail; head.Pre = tail; tail.Next = head; tail.Pre = head; }
// Removes the specified entry if it is inserted in the list. public static bool RemoveIfInserted(DListNode entry) { DListNode next, prev; if ((next = entry.next) == null) { return(false); } prev = entry.prev; next.prev = prev; prev.next = next; entry.next = entry.prev = null; // mark as removed! return(true); }
public SemaphoreAsync(int initial, int maximum) { if (initial < 0 || initial > maximum) { throw new ArgumentOutOfRangeException("initial"); } if (maximum <= 0) { throw new ArgumentOutOfRangeException("maximum"); } maxPermits = maximum; currentPermits = initial; DListNode.InitializeList(waiters); }
public void Release() { Waiter toFinish = null; lock (_lock) { if (currentPermits + 1 > maxPermits) { throw new ArgumentOutOfRangeException("releases"); } currentPermits += 1; Waiter waiter; while ((waiter = (Waiter)DListNode.FirstEntry(waiters)) != null) { if (Volatile.Read(ref waiter.state) != WAITING) { DListNode.RemoveIfInserted(waiter); continue; } if (waiter.TrySetState(SUCCESS)) { DListNode.RemoveIfInserted(waiter); currentPermits -= 1; toFinish = waiter; break; } } } // finish it outside the lock if (toFinish != null) { // cancel the active cancelers if (toFinish.ctkReg != null) { toFinish.ctkReg.Dispose(); } if (toFinish.timer != null) { toFinish.timer.Dispose(); } toFinish.tcs.SetResult(true); } }
public void OnCancellation(object state) { var waiter = (Waiter)state; if (waiter.TrySetState(CANCELED)) { if (DListNode.IsInList(waiter)) { lock (_lock) { DListNode.RemoveIfInserted(waiter); } } if (waiter.timer != null) { waiter.timer.Dispose(); } waiter.tcs.SetCanceled(); } }
public void Put(int key, int value) { if (_lruValDic.TryGetValue(key, out DListNode outNode)) { outNode.val = value; RemoveNode(outNode); AddNode(outNode); } else { var newDNode = new DListNode(key, value); AddNode(newDNode); _lruValDic.Add(key, newDNode); if (_lruValDic.Count > _size) { _lruValDic.Remove(head.Next.Key); RemoveNode(head.Next); } } }
public void OnTimeout(object state) { var waiter = (Waiter)state; if (waiter.TrySetState(CANCELED)) { if (DListNode.IsInList(waiter)) { lock (_lock) { DListNode.RemoveIfInserted(waiter); } } if (waiter.ctkReg != null) { waiter.ctkReg.Dispose(); } waiter.timer.Dispose(); waiter.tcs.SetResult(false); } }
//--------------------------------------------------------------------- // 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); } }
public void Release() { Waiter <Data> toFinish = null; lock (_lock) { if (currentPermits + 1 > maxPermits) { throw new ArgumentOutOfRangeException("releases"); } currentPermits += 1; Waiter <Data> waiter; while ((waiter = (Waiter <Data>)DListNode.FirstEntry(waiters)) != null) { if (Volatile.Read(ref waiter.state) != WaiterState.WAITING) { // Shouldn't already be on the queue, ensure it is removed DListNode.RemoveIfInserted(waiter); continue; } if (waiter.TrySetStateAndUnlink(WaiterState.SUCCESS)) { currentPermits -= 1; // queue node for further processing outside the lock waiter.prev = toFinish; toFinish = waiter; break; } } } // finish the stack of satisfied requests while (toFinish != null) { toFinish.OnSuccess(); toFinish = (Waiter <Data>)toFinish.prev; } }
public void RemoveNode(DListNode node) { node.Pre.Next = node.Next; node.Next.Pre = node.Pre; }
//--------------------------------------------------------------------- // 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); }
// Initializes a doubly-linked list. public static void InitializeList(DListNode list) { list.next = list.prev = list; }
// Returns the first entry of the list or null if the list is empty public static DListNode FirstEntry(DListNode list) { return(list.next == list ? null : list.next); }
// Returns true if the specified list is empty. public static bool IsListEmpty(DListNode list) { return(list.next == list); }
// Returns true of the specified ListNode is in a list public static bool IsInList(DListNode entry) { return(Volatile.Read(ref entry.next) == null); }