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