// do the acquire operation public AcquireResult Acquire(AcquireArgs acquireArgs) { _lock.Acquire(); try { while (!CanAcquire(acquireArgs)) { enqueue the current thread on the "waitQueue" sensible to posterior wakeups; int depth = _lock.ReleaseAll(); block current thread until it is waked up by a releaser thread; _lock.ReAcquire(depth); } return(AcquireSideEffect(acquireArgs)); } finally { _lock.Release(); } }
// generic acquire operation public AcquireResult Acquire(AcquireArgs acquireArgs) { _lock.Acquire(); try { if (reqQueue.Count == 0 && CanAcquire(acquireArgs)) { return(AcquireSideEffect(acquireArgs)); } Request request = new Request(acquireArgs); reqQueue.AddLast(request); // enqueue the "request" at the end of the request queue do { enqueue current thread on the "waitQueue" sensible to posterior wakeups done by "_lock" owners; int depth = _lock.ReleaseAll(); block current thread until it is waked up by a releaser thread; _lock.ReAcquire(depth); } while (!request.done); // the requested acquire operation completed successfully return(request.acquireResult); } finally { _lock.Release(); } }
// 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); } }
// executes the side effect processing related to a successful acquire private AcquireResult AcquireSideEffect(AcquireArgs acquireArgs) { update "synchState" according to "acquireArgs" after a successful acquire; returns "the-proper-acquire-result" }
// check if synchronization state allows an immediate acquire private bool CanAcquire(AcquireArgs acquireArgs) { returns true if "syncState" satisfies an immediate acquire according to "acquireArgs"; }
bool done; // true when the acquire is done Request(AcquireArgs args) { acquireArgs = args; }
// 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); } }
internal bool done; // true when the acquire is done internal Request(AcquireArgs args) { acquireArgs = args; }