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