/******************************************************************** * Copyright (C) 2018 by UCBL * * Initial author: Matthieu Moy * ********************************************************************/ #include #include #include #include #include #include using namespace std; #define NB_ROUNDS 10 #define NB_CARS 10 /* Pick a version here (Miralonde_Starve or Miralonde_Starve_Free) */ #define Miralonde Miralonde_Starve_Free /** * Simple version, but one direction may starve if cars come often * enough in the other direction. */ class Miralonde_Starve { public: void EntreeNS() { m.lock(); cout << "EntreeNS: request" << endl; while (nb_cars_SN != 0) { c.wait(m); } nb_cars_NS++; cout << "EntreeNS: pass" << endl; m.unlock(); } void EntreeSN() { m.lock(); cout << " EntreeSN: request" << endl; while (nb_cars_NS != 0) { c.wait(m); } nb_cars_SN++; cout << " EntreeSN: pass" << endl; m.unlock(); } void SortieNS() { m.lock(); cout << "SortieNS" << endl; nb_cars_NS--; c.notify_all(); m.unlock(); } void SortieSN() { m.lock(); cout << " SortieSN" << endl; nb_cars_SN--; c.notify_all(); m.unlock(); } private: int nb_cars_NS = 0; int nb_cars_SN = 0; mutex m; condition_variable_any c; }; /** * Starvation-free version of Miralonde. * * Cars can go if: * - nobody takes the other direction * - and : * - nobody's waiting on the other side, or * - previous car went the oposite way */ class Miralonde_Starve_Free { public: void EntreeNS() { m.lock(); cout << "EntreeNS: request" << endl; nb_cars_waiting_N++; while (not(nb_cars_SN == 0 && (nb_cars_waiting_S == 0 || current_direction == SN))) { c.wait(m); } nb_cars_waiting_N--; nb_cars_NS++; current_direction = NS; cout << "EntreeNS: pass" << endl; m.unlock(); } void EntreeSN() { m.lock(); cout << " EntreeSN: request" << endl; nb_cars_waiting_S++; while (not(nb_cars_NS == 0 && (nb_cars_waiting_N == 0 || current_direction == NS))) { c.wait(m); } nb_cars_waiting_S--; nb_cars_SN++; cout << " EntreeSN: pass" << endl; current_direction = SN; m.unlock(); } void SortieNS() { m.lock(); cout << "SortieNS" << endl; nb_cars_NS--; c.notify_all(); m.unlock(); } void SortieSN() { m.lock(); cout << " SortieSN" << endl; nb_cars_SN--; c.notify_all(); m.unlock(); } private: enum direction { NS, SN, }; direction current_direction = NS; int nb_cars_waiting_N = 0; int nb_cars_waiting_S = 0; int nb_cars_NS = 0; int nb_cars_SN = 0; mutex m; condition_variable_any c; }; /***** Tests *****/ void car_thread(Miralonde *m) { for (int i = 0; i < NB_ROUNDS; i++) { if (rand() % 2 == 0) usleep(100); m->EntreeNS(); if (rand() % 2 == 0) usleep(100); m->SortieNS(); if (rand() % 2 == 0) usleep(100); m->EntreeSN(); if (rand() % 2 == 0) usleep(100); m->SortieSN(); } } void car_unfair_NS(Miralonde *m) { m->EntreeNS(); sleep(1); m->SortieNS(); m->EntreeSN(); sleep(1); m->SortieSN(); } void car_unfair_SN(Miralonde *m) { m->EntreeSN(); sleep(1); m->SortieSN(); m->EntreeNS(); sleep(1); m->SortieNS(); } int main() { vector v; Miralonde m; v.push_back(thread(car_unfair_SN, &m)); v.push_back(thread(car_unfair_NS, &m)); usleep(10); for (int i = 0; i < NB_CARS; i++) { v.push_back(thread(car_thread, &m)); } for (thread &t : v) { t.join(); } }