private void Run() { int fail = 0; StWaitable[] ws = new StWaitable[] { s }; VConsole.WriteLine("+++ a #{0} started...", id); do { try { while (!s.Wait(1, new StCancelArgs((id & 1) + 1, shutdown))) { //while (!s.Wait(new StCancelArgs((n & 1) + 1, shutdown))) { //while (StWaitable.WaitAny(ws, new StCancelArgs((n & 1) + 1, shutdown)) == StParkStatus.Timeout) { //while (!StWaitable.WaitAll(ws, new StCancelArgs((n & 1) + 10, shutdown))) { if (shutdown.IsSet) { goto Exit; } fail++; //Thread.Sleep(0); } } catch (StThreadAlertedException) { break; } if ((++acquires[id] % 20000) == 0) { VConsole.Write("-{0}", id); } } while (!shutdown.IsSet); Exit: VConsole.WriteLine("+++ acquirer #{0} exiting: [{1}/{2}]", id, acquires[id], fail); done.Signal(); }
private void Run() { VConsole.WriteLine("+++ a #{0} started...", id); int fail = 0; do { try { int index = StWaitable.WaitAny(es, new StCancelArgs(1, shutdown)); if (index >= 0 && index < es.Length) { if ((++acquires[id] % 20000) == 0) { VConsole.Write("-{0}", id); } } else { fail++; } } catch (StThreadAlertedException) { break; } } while (true); VConsole.WriteLine("+++ a #{0} exiting: [{1}/{2}]", id, acquires[id], fail); done.Signal(); }
public static void GlobalThread(int id, bool waitAll) { int fail = 0; int count = 0; try { do { if (waitAll ? StWaitable.WaitAll(evts, new StCancelArgs(shutdown)) : StWaitable.WaitAny(evts, new StCancelArgs(id, shutdown)) != StParkStatus.Timeout) { count++; } else { fail++; } } while (!shutdown.IsSet); } catch (StThreadAlertedException) { } VConsole.WriteLine("+++ {0} (Wait{1}) exiting: {2}/{3}", Thread.CurrentThread.Name, waitAll ? "All" : "Any", count, fail); done.Signal(); }
private void Run() { VConsole.WriteLine("+++ a #{0} started...", id); int fail = 0; int index; do { try { index = StWaitable.WaitAny(ss, new StCancelArgs(1, shutdown)); if (index >= 0 && index < SEMAPHORES) { if ((++acquires[id] % 500) == 0) { VConsole.Write("-{0}", id); } } else { fail++; } } catch (StThreadAlertedException) { break; } //Thread.Sleep(0); } while (!shutdown.IsSet); VConsole.WriteLine("+++ a #{0} exiting, [{1}/{2}]", id, acquires[id], fail); done.Signal(); }
// // Constructors. // public StTimer(bool notificationTimer) { if (notificationTimer) { tmrEvent = new StNotificationEvent(); } else { tmrEvent = new StSynchronizationEvent(); } state = INACTIVE; cbparker = new CbParker(TimerCallback); timer = new RawTimer(cbparker); }
private static void Run(int id) { int fail = 0; var sem0 = new StSemaphore(0); var sem1 = new StSemaphore(0); var sem2 = new Semaphore(0, int.MaxValue); var sem3 = new Semaphore(0, int.MaxValue); var stsems = new[] { sem0, sem1 }; var whsems = new[] { sem2, sem3 }; VConsole.WriteLine("+++ w #{0} started...", id); do { ThreadPool.QueueUserWorkItem(delegate { sem0.Release(1); sem1.Release(1); Thread.Sleep(0); sem2.Release(1); sem3.Release(1); if (sem1.Wait(1, new StCancelArgs(0))) { Thread.Sleep(0); sem1.Release(1); } }); try { do { if (StWaitable.WaitAll(stsems, whsems, new StCancelArgs(id))) { break; } fail++; } while (true); } catch (StThreadAlertedException) { break; } if ((++counts[id] % 1000) == 0) { VConsole.Write("-{0}", id); } } while (shutdown == 0); VConsole.WriteLine("+++ w #{0} exiting: [{1}/{2}]", id, counts[id], fail); done.Signal(); }
public static void RingThread(int id) { int index = id; int count = 0; StWaitable.SignalAndWait(start, evts[index]); try { do { evts[index].Reset(); count++; index = (index + 1) & (RING_THREADS - 1); evts[index].Set(); evts[index].WaitOne(new StCancelArgs(shutdown)); } while (!shutdown.IsSet); } catch (StThreadAlertedException) { } counts[index] = count; VConsole.WriteLine("+++ {0} exiting: {1}", Thread.CurrentThread.Name, count); done.Signal(); }
// // WaitOne unconditionally until all the specified waitables // allow the acquire. // public static void WaitAll(StWaitable[] ws) { WaitAll(ws, StCancelArgs.None); }
/// <summary> /// Waits unconditionally until one of the specified waitables /// can be acquired. /// </summary> /// <param name="ws">The array of waitables.</param> /// <returns></returns> public static int WaitAny(StWaitable[] ws) { return WaitAny(ws, StCancelArgs.None); }
/// <summary> /// Waits until one of the specified waitables or wait handles can be /// acquired, activating the specified cancellers. /// </summary> /// <param name="ws">The array of waitables.</param> /// <param name="hs">The array of wait handles.</param> /// <param name="cargs">The cancellation arguments.</param> /// <returns></returns> public static int WaitAny(StWaitable[] ws, WaitHandle[] hs, StCancelArgs cargs) { if (ws == null) { throw new ArgumentNullException("ws"); } if (hs == null) { throw new ArgumentNullException("hs"); } int len = ws.Length; for (int i = 0; i < hs.Length; i++) { if (hs[i].WaitOne(0)) { return StParkStatus.Success + len + i; } } return WaitAnyInternal(ws, hs, cargs); }
internal static int WaitAnyInternal(StWaitable[] ws, WaitHandle[] hs, StCancelArgs cargs) { int len = ws.Length; // // First, we scan the *ws* array trying to acquire one of the // synchronizers. // for (int i = 0; i < len; i++) { if (ws[i]._TryAcquire()) { return StParkStatus.Success + i; } } if (cargs.Timeout == 0) { return StParkStatus.Timeout; } // // Create a parker and execute the WaitAny prologue on all // waitables. We stop executing prologues as soon as we detect // that the acquire operation was accomplished. // StParker pk = hs != null ? new StParker(EventBasedParkSpotFactory.Current. Create(new WaitAnyBehavior(hs, len))) : new StParker(1); WaitBlock[] wbs = new WaitBlock[len]; WaitBlock[] hints = new WaitBlock[len]; int lv = -1; int sc = 0; int gsc = 0; for (int i = 0; !pk.IsLocked && i < len; i++) { StWaitable w = ws[i]; if ((wbs[i] = w._WaitAnyPrologue(pk, i, ref hints[i], ref sc)) == null) { if (pk.TryLock()) { pk.UnparkSelf(i); } else { w._UndoAcquire(); } break; } // // Adjust the global spin count. // if (gsc < sc) { gsc = sc; } lv = i; } int wst = pk.Park(gsc, cargs); StWaitable acq = wst >= StParkStatus.Success && wst < len ? ws[wst] : null; // // Cancel the acquire attempt on all waitables where we executed // the WaitAny prologue, except the one we acquired. // for (int i = 0; i <= lv; i++) { StWaitable w = ws[i]; if (w != acq) { w._CancelAcquire(wbs[i], hints[i]); } } if (wst >= StParkStatus.Success && wst < len + (hs != null ? hs.Length : 0)) { if (acq != null) { acq._WaitEpilogue(); } return wst; } StCancelArgs.ThrowIfException(wst); return StParkStatus.Timeout; }
private void Run() { int count = 0; int failed = 0; Console.WriteLine("+++ ctrl #{0} starts...\n", id); Random rnd = new Random(Environment.TickCount * (id + 1)); StTimer[] timers = new StTimer[TIMERS]; for (int i = 0; i < TIMERS; i++) { timers[i] = new StTimer(true); } do { // // Start the timers. // int maxTime = 0; for (int i = 0; i < TIMERS; i++) { int delay = 100 + rnd.Next(500); timers[i].Set(delay, 0, TimerCallback, timers[i]); if (delay > maxTime) { maxTime = delay; } } int start = Environment.TickCount; try { int timeout = 350 + rnd.Next(500); if (StWaitable.WaitAll(timers, new StCancelArgs(timeout, shutdown))) { int elapsed = Environment.TickCount - start; Console.WriteLine("+++ ctrl #{0}, synchronized with its timers[{1}/{2}]\n", id, maxTime, elapsed); count++; Thread.Sleep(100); if (!shutdown.IsSet) { continue; } } else { int elapsed = Environment.TickCount - start; Console.WriteLine("--- ctrl #{0}, timed out({1}) expired[{2}/{3}]\n", id, timeout, maxTime, elapsed); } } catch (StThreadAlertedException) { Console.WriteLine("--- ctrl #{0}, CANCELLED\n", id); } // // Cancel the timers. // for (int i = 0; i < TIMERS; i++) { timers[i].Cancel(); } failed++; } while (!shutdown.IsSet); for (int i = 0; i < TIMERS; i++) { timers[i].Cancel(); } Console.WriteLine("+++ ctrl #{0} exiting after [{1}/{1}] synchs...\n", id, count, failed); done.Signal(); }
// // Sorts the waitable array by the waitable id and, at the same time, // check if all waitables allow an immediate acquire operation. // // NOTE: The notification events are not sorted, because they don't // have an acquire side-effect. The notification events are // grouped at the end of the sorted array. // private static int SortAndCheckAllowAcquire(StWaitable[] ws, StWaitable[] sws, out int nevts) { int i; StWaitable w; bool acqAll = true; int len = ws.Length; // // Find the first waitable that isn't a notification event, // in order to start insertion sort. // nevts = len; for (i = 0; i < len; i++) { w = ws[i]; acqAll &= w._AllowsAcquire; // // If the current waitable is a notification event, insert // it at the end of the ordered array; otherwise, insert it // on the begin of the array and break the loop. // if (w.id == NOTIFICATION_EVENT_ID) { sws[--nevts] = w; } else { sws[0] = w; break; } } // // If all synchronizers are notification events, return. // if (nevts == 0) { return acqAll ? 1 : 0; } // // Sort the remaining synchronizers using the insertion sort // algorithm but only with the non-notification event waitables. // int k = 1; for (i++; i < len; i++, k++) { w = ws[i]; acqAll &= w._AllowsAcquire; if (w.id == NOTIFICATION_EVENT_ID) { sws[--nevts] = w; } else { // // Find the insertion position for *w*. // sws[k] = w; int j = k - 1; while (j >= 0 && sws[j].Id > w.Id) { sws[j + 1] = sws[j]; j--; } // // Insert at j+1 position. // sws[j + 1] = w; // // Check for duplicates. // if (sws[k - 1] == sws[k]) { return -1; } } } return acqAll ? 1 : 0; }
internal static bool WaitAllInternal(StWaitable[] ws, WaitHandle[] hs, StCancelArgs cargs) { if (ws == null) { throw new ArgumentNullException("ws"); } int nevts; int len = ws.Length; StWaitable[] sws = new StWaitable[len]; WaitHandle[] shs = null; int waitHint = SortAndCheckAllowAcquire(ws, sws, out nevts); if (waitHint < 0) { throw new ArgumentException("There are duplicate waitables", "ws"); } if (hs != null) { shs = Sort(hs); if (shs == null) { throw new ArgumentException("There are duplicate wait handles", "hs"); } } if (waitHint != 0 && shs != null && !WaitHandle.WaitAll(shs, 0)) { waitHint = 0; } // // Return success if all synchronizers are notification events and are set. // if (waitHint != 0 && nevts == 0) { return true; } if (waitHint == 0 && cargs.Timeout == 0) { return false; } // // If a timeout was specified, get the current time in order // to adjust the timeout value later, if we re-wait. // int lastTime = (cargs.Timeout != Timeout.Infinite) ? Environment.TickCount : 0; WaitBlock[] wbs = null; WaitBlock[] hints = null; do { if (waitHint == 0) { // // Create the wait block arrays if this is the first time // that we execute the acquire-all prologue. // if (wbs == null) { wbs = new WaitBlock[len]; hints = new WaitBlock[len]; } // // Create a parker for cooperative release, specifying as many // releasers as the number of waitables. The parker because is // not reused because other threads may have references to it. // StParker pk = shs != null ? new StParker(len, EventBasedParkSpotFactory.Current. Create(new WaitAllBehavior(shs))) : new StParker(len); int gsc = 1; int sc = 0; for (int i = 0; i < len; i++) { if ((wbs[i] = sws[i]._WaitAllPrologue(pk, ref hints[i], ref sc)) == null) { if (pk.TryLock()) { pk.UnparkSelf(StParkStatus.StateChange); } } else if (gsc != 0) { if (sc == 0) { gsc = 0; } else if (sc > gsc) { gsc = sc; } } } int wst = pk.Park(gsc, cargs); // // If the wait was cancelled due to timeout, alert or interrupt, // cancel the acquire attempt on all waitables where we actually // inserted wait blocks. // if (wst != StParkStatus.StateChange) { for (int i = 0; i < len; i++) { WaitBlock wb = wbs[i]; if (wb != null) { sws[i]._CancelAcquire(wb, hints[i]); } } StCancelArgs.ThrowIfException(wst); return false; } } // // All waitables where we inserted wait blocks seem to allow // an immediate acquire operation; so, try to acquire all of // them that are not notification events. // int idx; for (idx = 0; idx < nevts; idx++) { if (!sws[idx]._TryAcquire()) { break; } } // // If all synchronizers were acquired, return success. // if (idx == nevts) { return true; } // // We failed to acquire all waitables, so undo the acquires // that we did above. // while (--idx >= 0) { sws[idx]._UndoAcquire(); } if (shs != null) { for (int i = 0; i < shs.Length; i++) { shs[i].UndoAcquire(); } } // // If a timeout was specified, adjust the timeout value // that will be used on the next wait. // if (!cargs.AdjustTimeout(ref lastTime)) { return false; } waitHint = 0; } while (true); }
/// <summary> /// Waits until all of the specified waitables or wait handles can be /// acquired, activating the specified cancellers. /// </summary> /// <param name="ws"></param> /// <param name="hs"></param> /// <param name="cargs"></param> /// <returns></returns> public static bool WaitAll(StWaitable[] ws, WaitHandle[] hs, StCancelArgs cargs) { if (hs == null) { throw new ArgumentNullException("hs"); } if (cargs.Alerter != null) { throw new ArgumentException("Cancellation through the alerter mechanism is not supported", "cargs"); } return WaitAllInternal(ws, hs, cargs); }
/// <summary> /// Waits until all of the specified waitables can be acquired, /// activating the specified cancellers. /// </summary> /// <param name="ws"></param> /// <param name="cargs"></param> /// <returns></returns> public static bool WaitAll(StWaitable[] ws, StCancelArgs cargs) { return WaitAllInternal(ws, null, cargs); }
// // Constructor: registers a wait with a Waitable synchronizer. // internal StRegisteredWait(StWaitable waitObject, WaitOrTimerCallback callback, object cbState, int timeout, bool executeOnce) { // // Validate the arguments. // if (timeout == 0) { throw new ArgumentOutOfRangeException("\"timeout\" can't be zero"); } if (callback == null) { throw new ArgumentOutOfRangeException("\"callback\" can't be null"); } if ((waitObject is StReentrantFairLock) || (waitObject is StReentrantReadWriteLock)) { throw new InvalidOperationException("can't register waits on reentrant locks"); } if ((waitObject is StNotificationEvent) && !executeOnce) { throw new InvalidOperationException("Notification event can't register waits" + " to execute more than once"); } // // Initialize the register wait fields // waitable = waitObject; cbparker = new CbParker(UnparkCallback); toTimer = new RawTimer(cbparker); this.timeout = timeout; this.executeOnce = executeOnce; this.callback = callback; this.cbState = (cbState != null) ? cbState : this; // // Execute the WaitAny prologue on the waitable. // int ignored = 0; waitBlock = waitObject._WaitAnyPrologue(cbparker, StParkStatus.Success, ref hint, ref ignored); // // Set the registered wait state to active and enable the // unpark callback. // state = ACTIVE; int ws = cbparker.EnableCallback(timeout, toTimer); if (ws != StParkStatus.Pending) { // // The acquire operation was already accomplished. To prevent // uncontrolled reentrancy, the unpark callback is executed inline. // UnparkCallback(ws); } }
// // Signals a waitable and waits on another as an atomic // operation, activating the specified cancellers. // public static bool SignalAndWait(StWaitable tos, StWaitable tow, StCancelArgs cargs) { // // Create a parker to execute the WaitAny prologue on the // *tow* waitable. // StParker pk = new StParker(); WaitBlock hint = null; int sc = 0; WaitBlock wb = tow._WaitAnyPrologue(pk, StParkStatus.Success, ref hint, ref sc); // // Signal the *tos* waitable. // if (!tos._Release()) { // // The signal operation failed. So, try to cancel the parker and, // if successful, cancel the acquire attempt; otherwise, wait until // the thread is unparked and, then, undo the acquire. // if (pk.TryCancel()) { tow._CancelAcquire(wb, hint); } else { pk.Park(); tow._UndoAcquire(); } // // Report the failure appropriately. // throw tos._SignalException; } // // Park the current thread, activating the specified cancellers // and spinning if appropriate. // int ws = pk.Park(sc, cargs); // // If we acquired, execute the WaitOne epilogue and return success. // if (ws == StParkStatus.Success) { tow._WaitEpilogue(); return true; } // // The acquire operation was cancelled; so, cancel the acquire // attempt and report the failure appropriately. // tow._CancelAcquire(wb, hint); StCancelArgs.ThrowIfException(ws); return false; }
// // Signals a waitable and waits unconditionally on another // as an atomic operation. // public static void SignalAndWait(StWaitable tos, StWaitable tow) { SignalAndWait(tos, tow, StCancelArgs.None); }
/// <summary> /// Waits until one of the specified waitables can be acquired, /// activating the specified cancellers. /// </summary> /// <param name="ws">The array of Waitables.</param> /// <param name="cargs">The cancellation arguments.</param> /// <returns></returns> public static int WaitAny(StWaitable[] ws, StCancelArgs cargs) { if (ws == null) { throw new ArgumentNullException("ws"); } return WaitAnyInternal(ws, null, cargs); }