libcruft-util/test/job/semaphore.cpp

71 lines
1.7 KiB
C++

#include "job/semaphore.hpp"
#include "job/flag.hpp"
#include "tap.hpp"
#include <thread>
#include <mutex>
///////////////////////////////////////////////////////////////////////////////
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<int> 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<std::thread> 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 ();
}