Improve robustness of merge_tests to schedule merges without spurious wakeups and in a wider stride of insertions

This commit is contained in:
Christian Mazakas
2023-05-09 13:33:50 -07:00
parent 69ba1c7c00
commit c2c34f96a3

View File

@@ -106,26 +106,38 @@ namespace {
std::condition_variable cv; std::condition_variable cv;
std::atomic_bool done1{false}, done2{false}; std::atomic_bool done1{false}, done2{false};
std::atomic<unsigned long long> num_merges{0}; std::atomic<unsigned long long> num_merges{0};
std::atomic<unsigned long long> call_count{0};
bool ready = false;
auto const old_mc = +raii::move_constructor; auto const old_mc = +raii::move_constructor;
BOOST_TEST_EQ(old_mc, 0u); BOOST_TEST_EQ(old_mc, 0u);
t1 = std::thread([&x1, &vals1, &l, &done1, &cv] { t1 = std::thread([&x1, &vals1, &l, &done1, &cv, &ready, &m] {
l.arrive_and_wait(); l.arrive_and_wait();
for (std::size_t idx = 0; idx < vals1.size(); ++idx) { for (std::size_t idx = 0; idx < vals1.size(); ++idx) {
auto const& val = vals1[idx]; auto const& val = vals1[idx];
x1.insert(val); x1.insert(val);
if (idx % 100 == 0) {
if (idx % (vals1.size() / 128) == 0) {
{
std::unique_lock<std::mutex> lk(m);
ready = true;
}
cv.notify_all(); cv.notify_all();
std::this_thread::yield(); std::this_thread::yield();
} }
} }
done1 = true; done1 = true;
{
std::unique_lock<std::mutex> lk(m);
ready = true;
}
cv.notify_all();
}); });
t2 = std::thread([&x2, &vals2, &l, &done2] { t2 = std::thread([&x2, &vals2, &l, &done2, &cv, &m, &ready] {
l.arrive_and_wait(); l.arrive_and_wait();
for (std::size_t idx = 0; idx < vals2.size(); ++idx) { for (std::size_t idx = 0; idx < vals2.size(); ++idx) {
@@ -137,27 +149,37 @@ namespace {
} }
done2 = true; done2 = true;
}); {
std::unique_lock<std::mutex> lk(m);
t3 = std::thread([&x1, &x2, &m, &cv, &done1, &done2, &num_merges] { ready = true;
while (x1.empty() && x2.empty()) {
} }
cv.notify_all();
do {
{
std::unique_lock<std::mutex> lk(m);
cv.wait(lk, [] { return true; });
}
num_merges += x1.merge(x2);
std::this_thread::yield();
num_merges += x2.merge(x1);
} while (!done1 || !done2);
BOOST_TEST(done1);
BOOST_TEST(done2);
}); });
t3 = std::thread(
[&x1, &x2, &m, &cv, &done1, &done2, &num_merges, &call_count, &ready] {
while (x1.empty() && x2.empty()) {
}
do {
{
std::unique_lock<std::mutex> lk(m);
cv.wait(lk, [&ready] { return ready; });
ready = false;
}
num_merges += x1.merge(x2);
std::this_thread::yield();
num_merges += x2.merge(x1);
call_count += 1;
} while (!done1 || !done2);
BOOST_TEST(done1);
BOOST_TEST(done2);
});
t1.join(); t1.join();
t2.join(); t2.join();
t3.join(); t3.join();
@@ -166,6 +188,7 @@ namespace {
// num merges is 0 most commonly in the cast of the limited_range // num merges is 0 most commonly in the cast of the limited_range
// generator as both maps will contains keys from 0 to 99 // generator as both maps will contains keys from 0 to 99
BOOST_TEST_EQ(+raii::move_constructor, 2 * num_merges); BOOST_TEST_EQ(+raii::move_constructor, 2 * num_merges);
BOOST_TEST_GE(call_count, 1u);
} }
x1.merge(x2); x1.merge(x2);