2018-03-23 14:10:20 +11:00
|
|
|
#include "thread/flag.hpp"
|
2019-06-22 15:46:34 +10:00
|
|
|
#include "thread/thread.hpp"
|
2018-03-14 15:22:45 +11:00
|
|
|
|
2019-06-22 15:46:34 +10:00
|
|
|
#include "tap.hpp"
|
2018-03-14 15:22:45 +11:00
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
main ()
|
|
|
|
{
|
2018-08-05 14:42:02 +10:00
|
|
|
cruft::TAP::logger tap;
|
2018-03-14 15:22:45 +11:00
|
|
|
|
2018-08-05 14:42:02 +10:00
|
|
|
cruft::thread::flag f;
|
2018-03-14 15:22:45 +11:00
|
|
|
std::atomic<int> value = 0;
|
|
|
|
|
2019-06-22 15:46:34 +10:00
|
|
|
cruft::thread::thread t1 ([&] () {
|
2018-03-14 15:22:45 +11:00
|
|
|
f.wait ();
|
|
|
|
value = 1;
|
|
|
|
});
|
|
|
|
|
2019-06-22 15:46:34 +10:00
|
|
|
cruft::thread::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");
|
2018-08-13 14:51:33 +10:00
|
|
|
f.notify_all ();
|
2018-03-14 15:22:45 +11:00
|
|
|
|
|
|
|
t1.join ();
|
|
|
|
tap.expect_eq (value, 1, "value has been changed after wait");
|
|
|
|
|
2019-06-22 15:46:34 +10:00
|
|
|
cruft::thread::thread t2 ([&] () {
|
2018-03-14 15:22:45 +11:00
|
|
|
f.wait ();
|
|
|
|
value = 2;
|
|
|
|
});
|
|
|
|
|
2019-06-22 15:46:34 +10:00
|
|
|
cruft::thread::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<
|
2018-08-05 14:42:02 +10:00
|
|
|
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)
|
2018-08-13 14:51:33 +10:00
|
|
|
row[i].notify_all ();
|
2018-03-20 18:02:20 +11:00
|
|
|
else
|
|
|
|
row[i].wait ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-06-22 15:46:34 +10:00
|
|
|
std::vector<cruft::thread::thread> workers;
|
2018-07-24 15:49:11 +10:00
|
|
|
std::generate_n (
|
|
|
|
std::back_inserter (workers),
|
|
|
|
parallelism,
|
|
|
|
[&, i = 0] () mutable
|
|
|
|
{
|
2019-06-22 15:46:34 +10:00
|
|
|
return cruft::thread::thread { func, i++ };
|
2018-07-24 15:49:11 +10:00
|
|
|
});
|
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
|
|
|
}
|