void spring_time::sleep(bool forceThreadSleep) { if (forceThreadSleep) { spring::this_thread::sleep_for(chrono::nanoseconds(toNanoSecsi())); return; } // for very short time intervals use a yielding loop (yield is ~5x more accurate than sleep(), check the UnitTest) if (toMicroSecsi() < (avgThreadSleepTimeMicroSecs + avgThreadYieldTimeMicroSecs * 5)) { const spring_time s = gettime(); while ((gettime() - s) < *this) thread_yield(); return; } // expected wakeup time const spring_time t0 = gettime() + *this; spring::this_thread::sleep_for(chrono::nanoseconds(toNanoSecsi())); const spring_time t1 = gettime(); const spring_time dt = t1 - t0; if (t1 >= t0) { // yes, it's not 100% thread correct, but it's okay when 1 of 1 million writes is dropped int avg = avgThreadSleepTimeMicroSecs.load(); int newAvg = mix<float>(avg, dt.toMicroSecsf(), 0.1f); avgThreadSleepTimeMicroSecs.store(newAvg); } }
static void thread_yield() { const spring_time t0 = spring_time::gettime(); this_thread::yield(); const spring_time t1 = spring_time::gettime(); const spring_time dt = t1 - t0; if (t1 >= t0) { // yes, it's not 100% thread correct, but it's okay when 1 of 1 million writes is dropped int avg = avgThreadYieldTimeMicroSecs.load(); int newAvg = mix<float>(avg, dt.toMicroSecsf(), 0.1f); avgThreadYieldTimeMicroSecs.store(newAvg); } }