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 // C includes 10 #include <stdio.h> 11 #include <stdint.h> 12 #include <stdlib.h> 13 14 // C++ includes 15 #include <chrono> 16 #include <mutex> 17 #include <random> 18 #include <thread> 19 20 std::thread g_thread_1; 21 std::thread g_thread_2; 22 std::thread g_thread_3; 23 std::mutex g_mask_mutex; 24 25 enum MaskAction { 26 eGet, 27 eAssign, 28 eClearBits 29 }; 30 31 uint32_t mask_access (MaskAction action, uint32_t mask = 0); 32 33 uint32_t 34 mask_access (MaskAction action, uint32_t mask) 35 { 36 static uint32_t g_mask = 0; 37 38 std::lock_guard<std::mutex> lock(g_mask_mutex); 39 switch (action) 40 { 41 case eGet: 42 break; 43 44 case eAssign: 45 g_mask |= mask; 46 break; 47 48 case eClearBits: 49 g_mask &= ~mask; 50 break; 51 } 52 return g_mask; 53 } 54 55 void * 56 thread_func (void *arg) 57 { 58 uint32_t thread_index = *((uint32_t *)arg); 59 uint32_t thread_mask = (1u << (thread_index)); 60 printf ("%s (thread index = %u) startng...\n", __FUNCTION__, thread_index); 61 62 std::default_random_engine generator; 63 std::uniform_int_distribution<int> distribution(0, 3000000); 64 65 while (mask_access(eGet) & thread_mask) 66 { 67 // random micro second sleep from zero to 3 seconds 68 int usec = distribution(generator); 69 printf ("%s (thread = %u) doing a usleep (%d)...\n", __FUNCTION__, thread_index, usec); 70 71 std::chrono::microseconds duration(usec); 72 std::this_thread::sleep_for(duration); 73 printf ("%s (thread = %u) after usleep ...\n", __FUNCTION__, thread_index); // Set break point at this line. 74 } 75 printf ("%s (thread index = %u) exiting...\n", __FUNCTION__, thread_index); 76 return NULL; 77 } 78 79 80 int main (int argc, char const *argv[]) 81 { 82 uint32_t thread_index_1 = 1; 83 uint32_t thread_index_2 = 2; 84 uint32_t thread_index_3 = 3; 85 uint32_t thread_mask_1 = (1u << thread_index_1); 86 uint32_t thread_mask_2 = (1u << thread_index_2); 87 uint32_t thread_mask_3 = (1u << thread_index_3); 88 89 // Make a mask that will keep all threads alive 90 mask_access (eAssign, thread_mask_1 | thread_mask_2 | thread_mask_3); // And that line. 91 92 // Create 3 threads 93 g_thread_1 = std::thread(thread_func, (void*)&thread_index_1); 94 g_thread_2 = std::thread(thread_func, (void*)&thread_index_2); 95 g_thread_3 = std::thread(thread_func, (void*)&thread_index_3); 96 97 char line[64]; 98 while (mask_access(eGet) != 0) 99 { 100 printf ("Enter thread index to kill or ENTER for all:\n"); 101 fflush (stdout); 102 // Kill threads by index, or ENTER for all threads 103 104 if (fgets (line, sizeof(line), stdin)) 105 { 106 if (line[0] == '\n' || line[0] == '\r' || line[0] == '\0') 107 { 108 printf ("Exiting all threads...\n"); 109 break; 110 } 111 int32_t index = strtoul (line, NULL, 0); 112 switch (index) 113 { 114 case 1: mask_access (eClearBits, thread_mask_1); break; 115 case 2: mask_access (eClearBits, thread_mask_2); break; 116 case 3: mask_access (eClearBits, thread_mask_3); break; 117 } 118 continue; 119 } 120 121 break; 122 } 123 124 // Clear all thread bits to they all exit 125 mask_access (eClearBits, UINT32_MAX); 126 127 // Join all of our threads 128 g_thread_1.join(); 129 g_thread_2.join(); 130 g_thread_3.join(); 131 132 return 0; 133 } 134