#include #include #include #include #include #include #include #include using namespace std; using namespace std::chrono; constexpr auto N = 1; constexpr auto DELAY = milliseconds(20); template void run(const char *name, Wait wait, Wake wake) { auto sync = barrier(2); auto time0 = high_resolution_clock::time_point(); auto dt = new double[N]; auto a = thread([&]() { for (int i = 0; i < N; ++i) { sync.arrive_and_wait(); wait(); auto time1 = high_resolution_clock::now(); auto delta = time1 - time0; dt[i] = delta.count() / 1e9; } }); auto b = thread([&]() { for (int i = 0; i < N; ++i) { sync.arrive_and_wait(); this_thread::sleep_for(DELAY); time0 = high_resolution_clock::now(); wake(); } }); a.join(); b.join(); sort(dt, dt + N); double avg = 0; double min = 1e99; double max = 0; double med = dt[N / 2]; for (int i = 0; i < N; ++i) { avg += dt[i]; if (dt[i] < min) min = dt[i]; if (dt[i] > max) max = dt[i]; } avg /= N; double sdev = 0; for (int i = 0; i < N; ++i) { double dev = dt[i] - avg; sdev += dev * dev; } sdev = sqrt(sdev / N); printf("%s avg: %.2f sdev: %.2f min: %.1f max: %.1f median: %.1f us\n", name, avg * 1e6, sdev * 1e6, min * 1e6, max * 1e6, med * 1e6); } int main() { { auto spin = atomic_bool(false); auto spin_wait = [&]() { while (!spin.load()); spin.store(false); }; auto spin_wake = [&]() { spin.store(true); }; run("Spin", spin_wait, spin_wake); } { auto atomic = atomic_bool(false); auto atomic_wait = [&]() { atomic.wait(false); atomic.store(false); }; auto atomic_wake = [&]() { atomic.store(true); atomic.notify_one(); }; run("Atomic wait/notify", atomic_wait, atomic_wake); } { auto semaphore = binary_semaphore(0); auto semaphore_wait = [&]() { semaphore.acquire(); }; auto semaphore_wake = [&]() { semaphore.release(); }; run("Semaphore", semaphore_wait, semaphore_wake); } { auto sleep = atomic_bool(false); auto sleep_wait = [&]() { while (!sleep.load()) this_thread::sleep_for(microseconds(1)); sleep.store(false); }; auto sleep_wake = [&]() { sleep.store(true); }; run("Sleep", sleep_wait, sleep_wake); } }