1 | #include <chrono> |
2 | #include <condition_variable> |
3 | #include <cstdio> |
4 | #include <thread> |
5 | |
6 | std::condition_variable g_condition_variable; |
7 | std::mutex g_mutex; |
8 | int g_count; |
9 | |
10 | char *g_char_ptr = nullptr; |
11 | |
12 | void |
13 | barrier_wait() |
14 | { |
15 | std::unique_lock<std::mutex> lock{g_mutex}; |
16 | if (--g_count > 0) |
17 | g_condition_variable.wait(lock&: lock); |
18 | else |
19 | g_condition_variable.notify_all(); |
20 | } |
21 | |
22 | void |
23 | do_bad_thing_with_location(unsigned index, char *char_ptr, char new_val) |
24 | { |
25 | unsigned what = new_val; |
26 | printf(format: "new value written to array(%p) and index(%u) = %u\n" , char_ptr, index, what); |
27 | char_ptr[index] = new_val; |
28 | } |
29 | |
30 | uint32_t |
31 | access_pool (bool flag = false) |
32 | { |
33 | static std::mutex g_access_mutex; |
34 | static unsigned idx = 0; // Well-behaving thread only writes into indexs from 0..6. |
35 | if (!flag) |
36 | g_access_mutex.lock(); |
37 | |
38 | // idx valid range is [0, 6]. |
39 | if (idx > 6) |
40 | idx = 0; |
41 | |
42 | if (flag) |
43 | { |
44 | // Write into a forbidden area. |
45 | do_bad_thing_with_location(index: 7, char_ptr: g_char_ptr, new_val: 99); |
46 | } |
47 | |
48 | unsigned index = idx++; |
49 | |
50 | if (!flag) |
51 | g_access_mutex.unlock(); |
52 | return g_char_ptr[index]; |
53 | } |
54 | |
55 | void |
56 | thread_func (uint32_t thread_index) |
57 | { |
58 | printf (format: "%s (thread index = %u) startng...\n" , __FUNCTION__, thread_index); |
59 | |
60 | barrier_wait(); |
61 | |
62 | uint32_t count = 0; |
63 | uint32_t val; |
64 | while (count++ < 15) |
65 | { |
66 | printf (format: "%s (thread = %u) sleeping for 1 second...\n" , __FUNCTION__, thread_index); |
67 | std::this_thread::sleep_for(rtime: std::chrono::seconds(1)); |
68 | |
69 | if (count < 7) |
70 | val = access_pool (); |
71 | else |
72 | val = access_pool (flag: true); |
73 | |
74 | printf (format: "%s (thread = %u) after sleep access_pool returns %d (count=%d)...\n" , __FUNCTION__, thread_index, val, count); |
75 | } |
76 | printf (format: "%s (thread index = %u) exiting...\n" , __FUNCTION__, thread_index); |
77 | } |
78 | |
79 | |
80 | int main (int argc, char const *argv[]) |
81 | { |
82 | g_count = 4; |
83 | std::thread threads[3]; |
84 | |
85 | g_char_ptr = new char[10]{}; |
86 | |
87 | // Create 3 threads |
88 | for (auto &thread : threads) |
89 | thread = std::thread{thread_func, std::distance(first: threads, last: &thread)}; |
90 | |
91 | struct { |
92 | int a; |
93 | int b; |
94 | int c; |
95 | } MyAggregateDataType; |
96 | |
97 | printf (format: "Before turning all three threads loose...\n" ); // Set break point at this line. |
98 | barrier_wait(); |
99 | |
100 | // Join all of our threads |
101 | for (auto &thread : threads) |
102 | thread.join(); |
103 | |
104 | delete[] g_char_ptr; |
105 | |
106 | return 0; |
107 | } |
108 | |