-template <template <typename> class Atom, bool SinglePoster, bool Blocking>
-void run_multi_producer_tests() {
- constexpr int NPROD = 5;
- Baton<Atom, SinglePoster, Blocking> local_ping[NPROD];
- Baton<Atom, SinglePoster, Blocking> local_pong[NPROD];
- Baton<Atom, /* SingleProducer = */ false, Blocking> global;
- Baton<Atom, SinglePoster, Blocking> shutdown;
-
- std::thread prod[NPROD];
- for (int i = 0; i < NPROD; ++i) {
- prod[i] = DSched::thread([&, i] {
- if (!std::is_same<Atom<int>, DeterministicAtomic<int>>::value) {
- // If we are using std::atomic (or EmulatedFutexAtomic) then
- // a variable sleep here will make it more likely that
- // global.post()-s will span more than one global.wait() by
- // the consumer thread and for the latter to block (if the
- // global baton is blocking). For DeterministicAtomic, we just
- // rely on DeterministicSchedule to do the scheduling. The
- // test won't fail if we lose the race, we just don't get
- // coverage.
- for (int j = 0; j < i; ++j) {
- std::this_thread::sleep_for(std::chrono::microseconds(1));
- }
- }
- local_ping[i].post();
- global.post();
- local_pong[i].wait();
- });
- }
-
- auto cons = DSched::thread([&] {
- while (true) {
- global.wait();
- global.reset();
- if (shutdown.try_wait()) {
- return;
- }
- for (int i = 0; i < NPROD; ++i) {
- if (local_ping.try_wait()) {
- local_ping.reset();
- local_pong.post();
- }
- }
- }
- });
-
- for (auto& t : prod) {
- DSched::join(t);
- }
-
- global.post();
- shutdown.post();
- DSched::join(cons);
-}
-