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