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
mask_access(MaskAction action,uint32_t mask)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 *
thread_func(void * arg)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 
main(int argc,char const * argv[])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