public E Take(int timeout) { lock (_monitor) { if (_sendRequestQueue.Count != 0) { SendRequest <E> sendRequest = _sendRequestQueue.First.Value; _sendRequestQueue.RemoveFirst(); if (sendRequest.IsBlocking) { sendRequest.Done = true; Monitor.Pulse(_monitor); } return(sendRequest.Message); } Request <E> request = new Request <E>(); _requestQueue.AddLast(request); TimeoutHolder timeoutHolder = new TimeoutHolder(timeout); do { try { if (timeoutHolder.Value <= 0L) { _requestQueue.Remove(request); return(default);
public Optional <E> receive(int timeout) { lock (_monitor) { var request = new RequestMessage <E>(true); waitingQueue.AddFirst(request); var timeoutHolder = new TimeoutHolder(timeout); do { try { if ((timeout = timeoutHolder.Value) <= 0) { waitingQueue.Remove(request); return(Optional <E> .Empty()); } Monitor.Wait(_monitor, timeout); } catch (ThreadInterruptedException tie) { if (!request.Busy) { waitingQueue.Remove(request); break; } throw; } } while (request.Busy); return(Optional <E> .Of(request.Message)); } }
// receive the nest message public bool Receive(out T receivedMessage, int timeout = Timeout.Infinite) { lock (monitor) { if (CanReceive()) { receivedMessage = ReceiveSideEffect(); return(true); } TimeoutHolder th = new TimeoutHolder(timeout); do { if ((timeout = th.Value) == 0) { receivedMessage = default(T); return(false); } try { Monitor.Wait(monitor, timeout); } catch (ThreadInterruptedException) { // .NET monitors can ignore notifications when there is a race between // the notification and the interrupt. So, we must regenerate the notification // if there are pending messages, in order to propagate the notification to // another blocked thread if (CanAcquire()) { Monitor.Pulse(monitor); } throw; } } while (!CanReceive()); receivedMessage = ReceiveSideEffect(); return(true); } }
// Wait until the event is signalled public bool Wait(int timeout = Timeout.Infinite) { lock (monitor) { // If the event is already signalled, return true if (signalState) { return(true); } // create an instance of TimeoutHolder to support timeout adjustments TimeoutHolder th = new TimeoutHolder(timeout); // loop until the event is signalled, the specified timeout expires or // the thread is interrupted. int arrivalGeneration = signalStateGeneration; do { if ((timeout = th.Value) == 0) { return(false); // timeout expired } Monitor.Wait(monitor, timeout); } while (arrivalGeneration == signalStateGeneration); return(true); } }
// Acquire one permit from the semaphore public bool Acquire(int timeout = Timeout.Infinite) { // try to acquire one permit, if available if (TryAcquire()) { return(true); } // no permits available; if a null time out was specified, return failure. if (timeout == 0) { return(false); } // if a time out was specified, get a time reference TimeoutHolder th = new TimeoutHolder(timeout); lock (monitor) { // the current thread declares itself as a waiter.. waiters++; /** * The .NET Memory Model does not guarantees non-reordering of previous volatile write * of "waiters" with the next volatile read of "permits", so we must EXPLICITLY * insert a Full Fence to ensure that this algorithm works! */ Interlocked.MemoryBarrier(); try { do { // after increment waiters, we must recheck if acquire is possible! if (TryAcquire()) { return(true); } // check if the specified timeout expired if ((timeout = th.Value) == 0) { return(false); } Monitor.Wait(monitor, timeout); } while (true); } catch (ThreadInterruptedException) { // if we were interrupted and there are permits available, we can have // been notified and interrupted. // so, we leave this method throwing ThreadInterruptException, but before // we regenerate the notification, if there are available permits // if (permits > 0) { Monitor.Pulse(monitor); } throw; // re-throw thread interrupted exception } finally { // the current thread is no longer a waiter waiters--; } } }
// Wait until the event is signalled public bool Wait(int timeout = Timeout.Infinite) { // If the event is signalled, return true if (tryAcquire()) { return(true); } // the event is not signalled; if a null time out was specified, return failure. if (timeout == 0) { return(false); } // if a time out was specified, get a time reference TimeoutHolder th = new TimeoutHolder(timeout); lock (monitor) { // get the current setVersion and declare the current thread as a waiter. int sv = setVersion; waiters++; /** * before we read the "signaled" volatile variable, we need to make sure that the increment * of *waiters* is visible to all processors. * In .NET this means interpose a full-fence memory barrier. */ Interlocked.MemoryBarrier(); try { /** * after declare this thread as waiter, we must recheck the "signaled" in order * to capture a check that ocorred befor we increment the waiters. */ if (tryAcquire()) { return(true); } // loop until the event is signalled, the specified timeout expires or // the thread is interrupted. do { // check if the wait timed out if ((timeout = th.Value) == 0) { // the specified time out elapsed, so return failure return(false); } Monitor.Wait(monitor, timeout); } while (sv == setVersion); return(true); } finally { // at the end, decrement the number of waiters waiters--; } } }
public bool Wait(int timeout) // throws InterruptedException { if (signaled) { return(true); } if (timeout == 0) { return(false); } lock (monitor) { int currentVersion = signalVersion; try { waiters++; // necessary to avoid reordering observation between the write // above and the read below (.Net permits this write-read reordering) Thread.MemoryBarrier(); if (signaled) { return(true); } // prepare wait TimeoutHolder th = new TimeoutHolder(timeout); do { Monitor.Wait(monitor, th.Value); if (currentVersion != signalVersion) { return(true); } if (th.Timeout) { return(false); // abort operation on timeout } }while (true); } catch (ThreadInterruptedException) { if (currentVersion != signalVersion) { Thread.CurrentThread.Interrupt(); return(true); } throw; } finally { waiters--; } } }
// acquires the specified number of permits; returns false if times out public bool Acquire(int acquires, int timeout = Timeout.Infinite) { lock (monitor) { if (reqQueue.Count == 0 && CanAcquire(acquires)) { AcquireSideEffect(acquires); return(true); } Request request = new Request(acquires); reqQueue.AddLast(request); // enqueue "request" at the end of "reqQueue" TimeoutHolder th = new TimeoutHolder(timeout); do { if ((timeout = th.Value) <= 0) { reqQueue.Remove(request); // after remove the request of the current thread from queue, *it is possible* // that the current synhcronization state allows now to satisfy other queued // acquire(s). if (CurrentSynchStateAllowsAcquire()) { PerformPossibleAcquires(); } return(false); } try { MonitorEx.Wait(monitor, request, timeout); // *wait on a private condition variable* } catch (ThreadInterruptedException) { // if the acquire operation was already done, re-assert interrupt // and return normally; else remove request from queue and throw // ThreadInterruptedException. if (request.done) { Thread.CurrentThread.Interrupt(); return(true); } reqQueue.Remove(request); // after remove the request of the current thread from queue, *it is possible* // that the current synhcronization state allows now to satisfy other queued // acquire(s). if (CurrentSynchStateAllowsAcquire()) { PerformPossibleAcquires(); } throw; // ThreadInterruptedException } } while (!request.done); // the request was completed return(true); } }
/** * Acquire operation. * @param timeout max waiting time * @return true if operation succeeded, false if timeout * @throws ThreadInterruptedException */ public bool Acquire(int timeout) // throws InterruptedException // fast path { if (tryAcquire()) { return(true); } if (timeout == 0) // fail! { return(false); } lock (monitor) { waiters++; // The following (complete) barrier is necessary on CLI to avoid reordering of the waiters write in line 43 // and the permits read on the execution of tryAcquire! Thread.MemoryBarrier(); if (tryAcquire()) // last try { waiters--; return(true); } try { // prepare wait TimeoutHolder th = new TimeoutHolder(timeout); do { int refTime = Environment.TickCount; Monitor.Wait(monitor, th.Remaining); if (tryAcquire()) { return(true); } if (th.Timeout) { return(false); } }while (true); } catch (ThreadInterruptedException e) { if (permits > 0) { Monitor.Pulse(monitor); } throw e; } finally { waiters--; } } }
public bool Acquire(int units, int timeout) { lock (monitor) { // non blocking path if (requests.Count == 0 && permits >= units) { permits -= units; return(true); } // try path if (timeout == 0) { return(false); } // prepare wait TimeoutHolder th = new TimeoutHolder(timeout); Request req = new Request(units); LinkedListNode <Request> node = requests.AddLast(req); do { try { req.Wait(monitor, th.Remaining); //Monitor.Wait(monitor, th.Remaining); if (node.Value.Processed) { return(true); } if (th.Timeout) { requests.Remove(node); notifyWaiters(); return(false); } } catch (ThreadInterruptedException) { if (node.Value.Processed) { Thread.CurrentThread.Interrupt(); return(true); } requests.Remove(node); notifyWaiters(); throw; } }while (true); } }
public bool Exchange(T mine, int timeout, out T yours) { yours = default(T); // just to satisfy the compiler lock (monitor) { if (current != null) // a partner is waiting... // process the pairing using execution delegation technique { yours = current.msg; current.msg = mine; Monitor.Pulse(monitor); current = null; // the pairing is done, so we must "hide" it return(true); } // prepare waiting PairRequest myPair = current = new PairRequest(mine); TimeoutHolder th = new TimeoutHolder(timeout); try { do { Monitor.Wait(monitor, th.Value); // check success if (!object.ReferenceEquals(myPair.msg, mine)) // the pairing is done { yours = myPair.msg; return(true); } // check timeout if (th.Timeout) { // abort current pairing current = null; return(false); } } while (true); } catch (ThreadInterruptedException) { if (!object.ReferenceEquals(myPair.msg, mine)) // the pairing is done { yours = myPair.msg; Thread.CurrentThread.Interrupt(); return(true); } // abort current pairing current = null; throw; } } }
public bool Acquire(int units, int timeout) // throws InterruptedException { lock (monitor) { // non blocking path if (permits >= units && waiters.Count == 0) { permits -= units; return(true); } if (timeout == 0) { return(false); } // blocking path // prepare wait TimeoutHolder th = new TimeoutHolder(timeout); var node = waiters.AddLast(new Request(units)); try { do { // use waiters node as a new condition! monitor.Wait(node, th.Value); if (node.Value.granted) { return(true); } if (th.Timeout) { waiters.Remove(node); notifyWaiters(); return(false); } }while (true); } catch (ThreadInterruptedException e) { if (node.Value.granted) { Thread.CurrentThread.Interrupt(); return(true); } waiters.Remove(node); notifyWaiters(); throw e; } } }
public bool Acquire(int timeout) { if (TryAcquire()) { return(true); } if (timeout == 0) { return(false); } TimeoutHolder th = new TimeoutHolder(timeout); lock (monitor) { waiters++; try { if (TryAcquire()) { return(true); } while (true) { Monitor.Wait(th.Value); if (TryAcquire()) { return(true); } if (th.Timeout) { return(false); } } } catch (ThreadInterruptedException) { if (permits > 0) { Monitor.Pulse(monitor); } throw; } finally { waiters--; } } }
public bool Transfer(E message, int timeout) { lock (_monitor) { if (_requestQueue.Count != 0) { Request <E> request = _requestQueue.First.Value; _requestQueue.RemoveFirst(); request.Message = message; request.Done = true; Monitor.Pulse(_monitor); } else { SendRequest <E> request = new SendRequest <E>(message, BLOCKING); _sendRequestQueue.AddLast(request); TimeoutHolder timeoutHolder = new TimeoutHolder(timeout); do { try { if (timeoutHolder.Value <= 0L) { _sendRequestQueue.Remove(request); return(false); } Monitor.Wait(_monitor, timeout); } catch (ThreadInterruptedException ie) { if (request.Done) { Thread.CurrentThread.Interrupt(); break; //will return true after the interruption, because the operation succeeded } _sendRequestQueue.Remove(request); throw ie; } } while (_requestQueue.Count == 0); } return(true); } }
public bool Wait(int timeout = Timeout.Infinite) { lock (monitor) { // If the event is already signalled, return true if (signalState) { return(true); } // enqueue a request on the request queue LinkedListNode <bool> requestNode = reqQueue.AddLast(false); // create an instance of TimeoutHolder to support timeout adjustments TimeoutHolder th = new TimeoutHolder(timeout); // loop until our request is satisfied, the specified timeout expires // or the thread is interrupted. do { if ((timeout = th.Value) == 0) { // remove our request from "reqQueue" reqQueue.Remove(requestNode); return(false); // return failure: timeout expired } try { Monitor.Wait(monitor, timeout); } catch (ThreadInterruptedException) { // as this acquire operation has no side effects we can choose to // throw ThreadInterruptedException instead of giving the operation // completed successfully. // anyway, we must remove the request from the queue if it is stiil // inserted. if (!requestNode.Value) { reqQueue.Remove(requestNode); } throw; } } while (!requestNode.Value); return(true); } }
public bool Acquire(int requests, int timeout) // throws InterruptedException { lock (monitor) { // non blocking path if (permits >= requests && waiters.Count > 0) { permits -= requests; return(true); } if (timeout == 0) { return(false); } // blocking path // prepare wait TimeoutHolder th = new TimeoutHolder(timeout); var node = waiters.AddLast(requests); try { do { Monitor.Wait(monitor, th.Value); if (waiters.First == node && permits >= requests) { waiters.RemoveFirst(); permits -= requests; notifyWaiters(); return(true); } if (th.Timeout) { waiters.Remove(node); notifyWaiters(); return(false); } }while (true); } catch (ThreadInterruptedException e) { waiters.Remove(node); notifyWaiters(); throw e; } } }
public Optional <T> Exchange(T mydata, int timeout) { lock (_lock) { if (_waiter != null) { Console.WriteLine("Swapee value = " + _waiter.MyData + ", swaper value = " + mydata); mydata = _waiter.Swap(mydata); _waiter.IsDone = true; Monitor.Pulse(_waiter.Lock); return(Optional <T> .Of(mydata)); } TimeoutHolder timeoutHolder = new TimeoutHolder(timeout); _waiter = new Waiter <T>(mydata, _lock); do { try { Console.WriteLine(_waiter.MyData); if ((timeout = timeoutHolder.Value) <= 0) { return(Optional <T> .Empty()); } Monitor.Wait(_waiter.Lock, timeout); } catch (ThreadInterruptedException e) { if (_waiter.IsDone) { Console.WriteLine("Done = true, value = " + _waiter.MyData); Thread.CurrentThread.Interrupt(); break; } throw; } } while (!_waiter.IsDone); Console.WriteLine("Will return value = " + _waiter.MyData); return(Optional <T> .Of(_waiter.MyData)); } }
// receive the next message from the queue public bool Receive(out T receivedMsg, int timeout = Timeout.Infinite) { lock (monitor) { if (reqQueue.Count == 0 && CanReceive()) { receivedMsg = ReceiveSideEffect(); return(true); } TimeoutHolder th = new TimeoutHolder(timeout); Request request = new Request(); reqQueue.AddLast(request); // enqueue "request" at the end of "reqQueue" do { if ((timeout = th.Value) == 0) { // the specified time limit has expired. // Here we know that our request was not satisfied. reqQueue.Remove(request); receivedMsg = default(T); return(false); } try { Monitor.Wait(monitor, timeout); } catch (ThreadInterruptedException) { // if the acquire operation was already done, re-assert interrupt // and return normally; else remove request from queue and throw // ThreadInterruptedException. if (request.done) { Thread.CurrentThread.Interrupt(); break; } // remove the request from queue and throw ThreadInterruptedException reqQueue.Remove(request); throw; } } while (!request.done); // the request was satisfied, retrieve the received message receivedMsg = request.receivedMsg; return(true); } }
// acquire "acquires" permits public bool Acquire(int acquires, int timeout = Timeout.Infinite) { lock (monitor) { if (CanAcquire(acquires)) { // there are sufficient permits available, take them AcquireSideEffect(acquires); return(true); } TimeoutHolder th = new TimeoutHolder(timeout); do { if ((timeout = th.Value) == 0) { return(false); } Monitor.Wait(monitor, timeout); } while (!CanAcquire(acquires)); AcquireSideEffect(acquires); return(true); } }
public bool Acquire(int timeout) // throws InterruptedException { lock (monitor) { // non blocking path if (permits > 0) { --permits; return(true); } if (timeout == 0) { return(false); } // blocking path TimeoutHolder th = new TimeoutHolder(timeout); try { do { Monitor.Wait(th.Value); if (permits > 0) { --permits; return(true); } if (th.Timeout) { return(false); } }while (true); } catch (ThreadInterruptedException e) { if (permits > 0) { Monitor.Pulse(monitor); } throw e; } } }
public bool Await(int timeout) { lock (monitor) { if (signaled) { return(true); } if (timeout == 0) { return(false); } TimeoutHolder th = new TimeoutHolder(timeout); int currVersion = notifyVersion; try { do { Monitor.Wait(monitor, th.Value); if (currVersion != notifyVersion) { return(true); } if (th.Timeout) { return(false); } }while (true); } catch (ThreadInterruptedException) { if (signaled) { Thread.CurrentThread.Interrupt(); return(true); } throw; } } }
public bool Acquire(int requests, int timeout) // throws InterruptedException { lock (monitor) { // non blocking path if (permits >= requests) { permits -= requests; return(true); } if (timeout == 0) { return(false); } // blocking path TimeoutHolder th = new TimeoutHolder(timeout); try { do { Monitor.Wait(monitor, th.Value); if (permits >= requests) { permits -= requests; return(true); } if (th.Timeout) { return(false); } }while (true); } catch (ThreadInterruptedException e) { // In this case no exception treatment is necessary // the catch clausule is redundant throw e; } } }
// The acquire operation public bool Acquire(AcquireArgs acquireArgs, out AcquireResult result, int timeout = Timeout.Infinite) { lock (monitor) { if (CanAcquire(acquireArgs)) { // do an immediate acquire result = AcquireSideEffect(acquireArgs); return(true); } TimeoutHolder th = new TimeoutHolder(timeout); do { if ((timeout = th.Value) == 0) { result = default(AcquireResult); return(false); } try { Monitor.Wait(monitor, timeout); } catch (ThreadInterruptedException) { // if notification was made with Monitor.Pulse, the single notification // may be lost if the blocking of the notified thread was interrupted, // so, if an acquire is possible, we notify another blocked thread, if any. // anyway we propagate the interrupted exception if (CanAcquire(acquireArgs)) { Monitor.Pulse(monitor); } throw; } } while (!CanAcquire(acquireArgs)); // now we can complete the acquire after blocking in the monitor result = AcquireSideEffect(acquireArgs); return(true); } }
// generic acquire operation; returns false when it times out public bool Acquire(AcquireArgs acquireArgs, out AcquireResult result, int timeout = Timeout.Infinite) { lock (monitor) { if (reqQueue.Count == 0 && CanAcquire(acquireArgs)) { result = AcquireSideEffect(acquireArgs); return(true); } Request request = new Request(acquireArgs); reqQueue.AddLast(request); // enqueue "request" at the end of the request queue TimeoutHolder th = new TimeoutHolder(timeout); do { if ((timeout = th.Value) == 0) { // the timeout limit has expired - here we are sure that the acquire resquest // is still pending. So, we remove the request from the queue and return failure. reqQueue.Remove(request); // After remove the request of the current thread from queue, *it is possible* // that the current synhcronization state allows now to satisfy other queued // acquire(s). if (CurrentSynchStateAllowsAquire()) { PerformPossibleAcquires(); } result = default(AcquireResult); return(false); } try { MonitorEx.Wait(monitor, request, timeout); // *wait on a private condition var* } catch (ThreadInterruptedException) { // the thread may be interrupted when the requested acquire operation // is already performed, in which case you can no longer give up if (request.done) { // re-assert the interrupt and return normally, indicating to the // caller that the operation was successfully completed Thread.CurrentThread.Interrupt(); break; } // remove the request from the queue and throw ThreadInterruptedException reqQueue.Remove(request); // After remove the request of the current thread from queue, *it is possible* // that the current synhcronization state allows now to satisfy other queued // acquire(s). if (CurrentSynchStateAllowsAquire()) { PerformPossibleAcquires(); } throw; // ThreadInterruptedException } } while (!request.done); // the request acquire operation completed successfully result = request.acquireResult; return(true); } }
public Optional <E> Get(int timeout) { lock (_monitor) { /* * If exception has occurred, then every calls to get result * in that same exception getting thrown again */ if (_state == State.Error) { throw _exceptionOccurred; } /* * If the value is already computed and the number of lives is greater than 0, * then the value is returned to caller right away. */ if (_currentLives > 0 && _state == State.Computed) { return(DecrementCheckAndReturn()); } /* * In any other case, either the value needs to be recalculated, or is already being * computed by another thread. The current thread calculate the value, or wait, * if the latter is the case. */ if (_state == State.Computing) { var timeoutHolder = new TimeoutHolder(timeout); do { if ((timeout = timeoutHolder.Value) < 0L) { return(Optional <E> .Empty()); } Monitor.Wait(_monitor, timeout); if (_state == State.Computed && _currentLives > 0) { return(DecrementCheckAndReturn()); } if (_state == State.Error) { throw _exceptionOccurred; } } while (_state == State.Computing); } _state = State.Computing; } /* * The current thread is going to calculate the new value, by invoking the supplier. */ E v = default; Exception ex = default; try { v = _supplier(); _currentLives = _lives; } catch (Exception e) { ex = e; } /* * In the end, if an unchecked exception has occurred, it shall be thrown, and State state * shall be put to ERROR. Else, the value field is updated and returned. */ lock (_monitor) { Monitor.PulseAll(_monitor); if (ex != null) { _exceptionOccurred = ex; _state = State.Error; throw _exceptionOccurred; } _value = v; _state = State.Computed; return(DecrementCheckAndReturn()); } }
public TimeoutHolder Timeout(float time, Action callback) { var th = new TimeoutHolder { Time = time, Callback = callback }; timeouts.Add(th); return th; }
public async static Task <Response> ShutDown(Request request) { if (toShutDown) { return new Response { Status = 503, Payload = toShutDownPayload } } ; toShutDown = true; if (inServiceRequests == 0) { return new Response { Status = 200, Payload = toShutDownPayload } } ; String tHeader; int timeout; request.Headers.TryGetValue("timeout", out tHeader); if (tHeader == null) { timeout = Timeout.Infinite; } else { int.TryParse(tHeader, out timeout); } TimeoutHolder th = new TimeoutHolder(timeout); lock (_lock) { do { try { if ((timeout = th.Value) == 0) { return(new Response { Status = 204, Payload = timeoutPayload }); } else if (inServiceRequests == 0) { return new Response { Status = 200, Payload = toShutDownPayload } } ; Monitor.Wait(_lock, timeout); } catch (ThreadInterruptedException) { if (inServiceRequests == 0) { return new Response { Status = 200, Payload = toShutDownPayload } } ; else { return new Response { Status = 500, Payload = serverError } }; } } while (true); } } } }
//--------------------------------------------------------------------- // 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); }
public void CancelTimeout(TimeoutHolder timeout) { timeouts.Remove(timeout); }