Lock Challenge Step 3
Syncmultiplethreadssharingaresource
main_no_debug.cpp
Go to the documentation of this file.
1 
11 
12 
13 #include <iostream> // std::cout
14 #include <thread> // std::thread
15 #include <mutex> // std::mutex, std::adopt_lock, std::unique_lock
16 #include <chrono> // std::chrono
17 #include <condition_variable> // std::condition_variable
18 #include <random> // std::default_random_generator
19 
20 #include "LockGuard.h" // chal::LockGuard
21 
22 #define NUM_THDS 3 // number of threads to execute
23 
24 
25 // Globals
26 std::mutex mtx; // shared mutex
27 std::condition_variable cond; // shared condition variable
28 
29 
30 
40 void thd_printer(int id, std::string msg) {
41 
42  std::cout << "thread" << id+1 << ": " << msg << std::endl;
43 }
44 
45 
57 void thd_worker (const int id, int &next_thd, std::default_random_engine &rand_e) {
58 
59  int wait_tm;
60 
61  thd_printer(id, "starting, waiting.");
62 
63  // repeat forever
64  while(1) {
65 
66  // lock mutex
67  mtx.lock();
68  std::unique_lock<std::mutex> locker (mtx, std::adopt_lock);
69 
70  // wait for condition signal
71  // Upon condition signal, check if current thread is next
72  // if yes continue, if not keep waiting
73  // lambda function creates condition predicate
74  cond.wait(locker, [&]() { return id == next_thd; });
75 
76  thd_printer(id, "signal received, doing work ....");
77 
78  // generate pseudo-random value between 1 and 5 seconds
79  wait_tm = 1 + rand_e() % 5;
80 
81  // sleep to simulate work
82  std::this_thread::sleep_for(std::chrono::seconds(wait_tm));
83 
84  thd_printer(id, "done with work, signal next thread");
85 
86  // if topmost thread, reset next_thd
87  if(next_thd == NUM_THDS-1)
88  next_thd = 0;
89  else
90  ++next_thd;
91 
92  cond.notify_all();
93  }
94 }
95 
96 
97 
98 int main () {
99 
100  std::thread threads[NUM_THDS];
101  int next_thd = -1; // prevent a spurious wake from prematurely activating thread 0
102 
103  std::default_random_engine rand_e;
104 
105  std::cout << "main: starting all threads" << std::endl;
106 
107  // spawn NUM_THDS threads:
108  for ( int i=0; i<NUM_THDS; ++i ) {
109 
110  // populate the array of thread objects
111  // pass in: * their unique ID by value
112  // * an integer to keep track of thread order by reference
113  // * a shared psuedo-random number generator by reference
114  threads[i] = std::thread(thd_worker, i, std::ref(next_thd), std::ref(rand_e));
115  }
116 
118  std::this_thread::sleep_for(std::chrono::seconds(3));
119 
120  cond.notify_all(); // start sequence
121  next_thd = 0; // allow thread 0 to be activated
122 
123  // clean up
124  for ( auto& th : threads ) {
125  th.join();
126  }
127 
128  return 0;
129 }
#define NUM_THDS
void thd_printer(int id, std::string msg)
thread print function
std::mutex mtx
std::condition_variable cond
void thd_worker(const int id, int &next_thd, std::default_random_engine &rand_e)
thread worker function
int main()