/// <summary> /// Temporarily sets the system wait precision to 1 ms. It will be revoked after the specified time or when this process ends. /// If already set, just updates the revoking time. /// </summary> /// <param name="endAfterMS">Revoke after this time, milliseconds.</param> /// <example> /// <code><![CDATA[ /// AOutput.Write(ATime.SleepPrecision_.Current); //probably 15.625 /// ATime.SleepPrecision_.TempSet1(500); /// AOutput.Write(ATime.SleepPrecision_.Current); //1 /// Thread.Sleep(600); /// AOutput.Write(ATime.SleepPrecision_.Current); //probably 15.625 again /// ]]></code> /// </example> public static void TempSet1(int endAfterMS = 1111) { lock ("2KgpjPxRck+ouUuRC4uBYg") { s_TS1_EndTime = WinMillisecondsWithoutSleep + endAfterMS; if (s_TS1_Obj == null) { s_TS1_Obj = new SleepPrecision_(1); //info: instead could call the API directly, but may need to auto-revoke using the finalizer ThreadPool.QueueUserWorkItem(endAfterMS2 => { Thread.Sleep((int)endAfterMS2); //note: don't use captured variables. It creates new garbage all the time. for (; ;) { int t; lock ("2KgpjPxRck+ouUuRC4uBYg") { t = (int)(s_TS1_EndTime - WinMillisecondsWithoutSleep); if (t <= 0) { s_TS1_Obj.Dispose(); s_TS1_Obj = null; break; } } Thread.Sleep(t); } }, endAfterMS); //perf: single QueueUserWorkItem adds 3 threads, >=2 adds 5. But Thread.Start is too slow etc. //QueueUserWorkItem speed first time is similar to Thread.Start, then ~8. //Task.Run and Task.Delay are much much slower first time. Single Delay adds 5 threads. } } //tested: Task Manager shows 0% CPU. If we set/revoke period for each Sleep(1) in loop, shows ~0.5% CPU. }
/// <summary> /// Waits <i>timeMilliseconds</i> milliseconds. /// </summary> /// <param name="timeMilliseconds">Time to wait, milliseconds. Or <see cref="Timeout.Infinite"/> (-1).</param> /// <remarks> /// Calls <see cref="Thread.Sleep(int)"/>. /// Does not process Windows messages and other events, therefore should not be used in threads with windows, timers, hooks, events or COM, unless <i>timeMilliseconds</i> is small. Supports APC. /// If the computer goes to sleep or hibernate during that time, the real time is the specified time + the sleep/hibernate time. /// /// Tip: the script editor replaces code like <c>100ms</c> with <c>100.ms();</c> when typing. /// </remarks> /// <exception cref="ArgumentOutOfRangeException"><i>timeMilliseconds</i> is negative and not Timeout.Infinite (-1).</exception> /// <example> /// <code><![CDATA[ /// wait.ms(500); /// 500.ms(); //the same (ms is an extension method) /// wait.s(0.5); //the same /// ]]></code> /// </example> public static void ms(this int timeMilliseconds) { SleepPrecision_.TempSet1_(timeMilliseconds); if (timeMilliseconds < 2000) { Thread.Sleep(timeMilliseconds); } else //workaround for Thread.Sleep bug: if there are APC, returns too soon after sleep/hibernate. { g1: long t = computer.tickCountWithoutSleep; Thread.Sleep(timeMilliseconds); t = timeMilliseconds - (computer.tickCountWithoutSleep - t); if (t >= 500) { timeMilliseconds = (int)t; goto g1; } } }
/// <summary> /// Same as <b>doEvents(int)</b> but with parameter <i>noSetPrecision</i>. /// </summary> internal static void SleepDoEvents_(int timeMS, bool noSetPrecision = false) { if (timeMS < 0 && timeMS != -1) { throw new ArgumentOutOfRangeException(); } if (timeMS == 0) { doEvents(); return; } if (!noSetPrecision) { SleepPrecision_.TempSet1_(timeMS); } Wait_(timeMS, WHFlags.DoEvents, null, null); }