1 #include <chrono>
2 #include <condition_variable>
3 #include <cstdio>
4 #include <random>
5 #include <thread>
6 
7 std::default_random_engine g_random_engine{std::random_device{}()};
8 std::uniform_int_distribution<> g_distribution{0, 3000000};
9 std::condition_variable g_condition_variable;
10 std::mutex g_mutex;
11 int g_count;
12 
13 char *g_char_ptr = nullptr;
14 
15 void
barrier_wait()16 barrier_wait()
17 {
18     std::unique_lock<std::mutex> lock{g_mutex};
19     if (--g_count > 0)
20         g_condition_variable.wait(lock);
21     else
22         g_condition_variable.notify_all();
23 }
24 
25 void
do_bad_thing_with_location(char * char_ptr,char new_val)26 do_bad_thing_with_location(char *char_ptr, char new_val)
27 {
28     *char_ptr = new_val;
29 }
30 
31 uint32_t
access_pool(bool flag=false)32 access_pool (bool flag = false)
33 {
34     static std::mutex g_access_mutex;
35     if (!flag)
36         g_access_mutex.lock();
37 
38     char old_val = *g_char_ptr;
39     if (flag)
40         do_bad_thing_with_location(g_char_ptr, old_val + 1);
41 
42     if (!flag)
43         g_access_mutex.unlock();
44     return *g_char_ptr;
45 }
46 
47 void
thread_func(uint32_t thread_index)48 thread_func (uint32_t thread_index)
49 {
50     printf ("%s (thread index = %u) startng...\n", __FUNCTION__, thread_index);
51 
52     barrier_wait();
53 
54     uint32_t count = 0;
55     uint32_t val;
56     while (count++ < 15)
57     {
58         // random micro second sleep from zero to 3 seconds
59         int usec = g_distribution(g_random_engine);
60         printf ("%s (thread = %u) doing a usleep (%d)...\n", __FUNCTION__, thread_index, usec);
61         std::this_thread::sleep_for(std::chrono::microseconds{usec});
62 
63         if (count < 7)
64             val = access_pool ();
65         else
66             val = access_pool (true);
67 
68         printf ("%s (thread = %u) after usleep access_pool returns %d (count=%d)...\n", __FUNCTION__, thread_index, val, count);
69     }
70     printf ("%s (thread index = %u) exiting...\n", __FUNCTION__, thread_index);
71 }
72 
73 
main(int argc,char const * argv[])74 int main (int argc, char const *argv[])
75 {
76     g_count = 4;
77     std::thread threads[3];
78 
79     g_char_ptr = new char{};
80 
81     // Create 3 threads
82     for (auto &thread : threads)
83         thread = std::thread{thread_func, std::distance(threads, &thread)};
84 
85     printf ("Before turning all three threads loose...\n"); // Set break point at this line.
86     barrier_wait();
87 
88     // Join all of our threads
89     for (auto &thread : threads)
90         thread.join();
91 
92     delete g_char_ptr;
93 
94     return 0;
95 }
96