#include "job/semaphore.hpp" #include "job/flag.hpp" #include "tap.hpp" #include #include /////////////////////////////////////////////////////////////////////////////// void fight (util::job::semaphore &sem, const int iterations) { for (int i = 0; i < iterations; ++i) std::lock_guard {sem}; } /////////////////////////////////////////////////////////////////////////////// int main () { util::TAP::logger tap; { util::job::semaphore sem (0); tap.expect_eq (sem.value (), 0, "initialisation is respected"); tap.expect_eq (sem.unlock (), 1, "bare release increments without blocking"); tap.expect_eq (sem.lock (), 0, "bare acquire decrements without blocking"); } { util::job::semaphore sem (1); std::atomic test = 0; std::thread t ([&] () { sem.lock (); sem.lock (); test = 1; }); while (sem.value () > 0) std::this_thread::yield (); tap.expect_eq (test, 0, "locking blocks in foreign thread"); sem.unlock (); t.join (); tap.expect_eq (test, 1, "unlocking resumes foreign thread"); } { const auto parallelism = std::thread::hardware_concurrency (); constexpr int iterations = 1 << 16; std::vector threads; util::job::semaphore sem (0); for (unsigned i = 0; i < parallelism; ++i) threads.emplace_back (fight, std::ref (sem), iterations); sem.unlock (); sem.unlock (); for (auto &t: threads) t.join (); tap.expect (true, "high concurrency didn't deadlock"); } return tap.status (); }