2018-03-23 14:10:20 +11:00
|
|
|
#include "thread/semaphore.hpp"
|
|
|
|
#include "thread/flag.hpp"
|
2018-03-14 18:12:34 +11:00
|
|
|
#include "tap.hpp"
|
|
|
|
|
|
|
|
#include <thread>
|
|
|
|
#include <mutex>
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
void
|
2018-08-05 14:42:02 +10:00
|
|
|
fight (cruft::thread::semaphore &sem, const int iterations)
|
2018-03-14 18:12:34 +11:00
|
|
|
{
|
|
|
|
for (int i = 0; i < iterations; ++i)
|
|
|
|
std::lock_guard {sem};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
int
|
|
|
|
main ()
|
|
|
|
{
|
2018-08-05 14:42:02 +10:00
|
|
|
cruft::TAP::logger tap;
|
2018-03-14 18:12:34 +11:00
|
|
|
|
|
|
|
{
|
2018-08-05 14:42:02 +10:00
|
|
|
cruft::thread::semaphore sem (0);
|
2018-03-14 18:12:34 +11:00
|
|
|
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");
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2018-08-05 14:42:02 +10:00
|
|
|
cruft::thread::semaphore sem (1);
|
2018-03-14 18:12:34 +11:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2018-08-05 14:42:02 +10:00
|
|
|
cruft::thread::semaphore sem (0);
|
2018-03-14 18:12:34 +11:00
|
|
|
|
|
|
|
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 ();
|
|
|
|
}
|