libcruft-util/test/thread/flag.cpp

80 lines
1.9 KiB
C++
Raw Permalink Normal View History

#include <cruft/util/thread/flag.hpp>
2018-03-14 15:22:45 +11:00
#include <cruft/util/tap.hpp>
2018-03-14 15:22:45 +11:00
#include <thread>
2018-03-14 15:22:45 +11:00
int
main ()
{
cruft::TAP::logger tap;
2018-03-14 15:22:45 +11:00
cruft::thread::flag f;
2018-03-14 15:22:45 +11:00
std::atomic<int> value = 0;
std::thread t1 ([&] () {
2018-03-14 15:22:45 +11:00
f.wait ();
value = 1;
});
std::this_thread::sleep_for (std::chrono::milliseconds (100));
2018-03-14 15:22:45 +11:00
tap.expect_eq (value, 0, "value hasn't been set during wait");
f.notify_all ();
2018-03-14 15:22:45 +11:00
t1.join ();
tap.expect_eq (value, 1, "value has been changed after wait");
std::thread t2 ([&] () {
2018-03-14 15:22:45 +11:00
f.wait ();
value = 2;
});
std::this_thread::sleep_for (std::chrono::milliseconds (100));
2018-03-14 15:22:45 +11:00
tap.expect_eq (value, 2, "second wait didn't appear to block");
t2.join ();
2018-03-20 18:02:20 +11:00
{
// perform a stress test to (hopefully) discover deadlocks
//
// * create a large matrix of flag variables
// * create a bank of threads which:
// * wait on each flag of each row, or
// * notify if the flag index matches the thread index
constexpr int iterations = 1024;
constexpr int parallelism = 16;
std::vector<
std::array<cruft::thread::flag,parallelism>
2018-03-20 18:02:20 +11:00
> flags (iterations);
const auto func = [&flags] (const int idx) {
for (auto &row: flags) {
for (int i = 0; i < parallelism; ++i) {
if (i == idx)
row[i].notify_all ();
2018-03-20 18:02:20 +11:00
else
row[i].wait ();
}
}
};
std::vector<std::thread> workers;
std::generate_n (
std::back_inserter (workers),
parallelism,
[&, i = 0] () mutable
{
return std::thread { func, i++ };
});
2018-03-20 18:02:20 +11:00
for (auto &t: workers)
t.join ();
tap.expect (true, "flag sequence did not block");
}
2018-03-14 15:22:45 +11:00
return tap.status ();
2018-03-20 18:02:20 +11:00
}