#include #include #include #include int main () { cruft::TAP::logger tap; { // Ensure trivial success/failure notifications work cruft::parallel::stack values (1); tap.expect_eq (values.push (0), true, "uncontested empty push succeeds"); tap.expect_eq (values.push (0), false, "uncontested full push fails"); int out; tap.expect_eq (values.pop (&out), true, "uncontested full pop succeeds"); // Use a nullptr to test this case so that we know if the output // variable is dereferenced before the capacity is tested. tap.expect_eq (values.pop (nullptr), false, "uncontested empty pop fails"); } { static constexpr int COUNT = 4; cruft::parallel::stack values (COUNT); bool success = true; for (int i = 0; i < COUNT; ++i) success = success && values.push (i); for (int i = COUNT - 1; success && i >= 0; --i) { int res = -1; success = success && values.pop (&res); success = success && res == i; } tap.expect (success, "simple popped value sequence matches expected"); } { auto fight = [] (cruft::parallel::stack &store, cruft::thread::flag &ev, int iterations) { ev.wait (); while (iterations--) { while (!store.push (iterations)) ; for (int res; !store.pop (&res); ) ; } }; static int constexpr ITERATIONS = 8 * 1024; cruft::parallel::stack store (8); cruft::thread::flag ev; std::vector contestants; for (unsigned i = 0; i < std::thread::hardware_concurrency () + 1; ++i) contestants.emplace_back (fight, std::ref (store), std::ref (ev), ITERATIONS); ev.notify_all (); for (auto &t: contestants) t.join (); tap.expect (true, "n-way fight, {} contestants", contestants.size ()); } return tap.status (); }