1 #include "pseudo_barrier.h" 2 #include "thread.h" 3 #include <atomic> 4 #include <chrono> 5 #include <cinttypes> 6 #include <csignal> 7 #include <cstdio> 8 #include <cstdlib> 9 #include <cstring> 10 #include <mutex> 11 #include <thread> 12 #include <unistd.h> 13 #include <vector> 14 15 pseudo_barrier_t barrier; 16 std::mutex print_mutex; 17 std::atomic<bool> can_work; 18 thread_local volatile sig_atomic_t can_exit_now = false; 19 sigint_handler(int signo)20static void sigint_handler(int signo) {} 21 sigusr1_handler(int signo)22static void sigusr1_handler(int signo) { 23 std::lock_guard<std::mutex> lock{print_mutex}; 24 std::printf("received SIGUSR1 on thread id: %" PRIx64 "\n", get_thread_id()); 25 can_exit_now = true; 26 } 27 thread_func()28static void thread_func() { 29 // this ensures that all threads start before we stop 30 pseudo_barrier_wait(barrier); 31 32 // wait till the main thread indicates that we can go 33 // (note: using a mutex here causes hang on FreeBSD when another thread 34 // is suspended) 35 while (!can_work.load()) 36 std::this_thread::sleep_for(std::chrono::milliseconds(50)); 37 38 // the mutex guarantees that two writes don't get interspersed 39 { 40 std::lock_guard<std::mutex> lock{print_mutex}; 41 std::printf("thread %" PRIx64 " running\n", get_thread_id()); 42 } 43 44 // give other threads a fair chance to run 45 for (int i = 0; i < 5; ++i) { 46 std::this_thread::yield(); 47 std::this_thread::sleep_for(std::chrono::milliseconds(200)); 48 if (can_exit_now) 49 return; 50 } 51 52 // if we didn't get signaled, terminate the program explicitly. 53 _exit(0); 54 } 55 main(int argc,char ** argv)56int main(int argc, char **argv) { 57 int num = atoi(argv[1]); 58 59 pseudo_barrier_init(barrier, num + 1); 60 61 signal(SIGINT, sigint_handler); 62 signal(SIGUSR1, sigusr1_handler); 63 64 std::vector<std::thread> threads; 65 for (int i = 0; i < num; ++i) 66 threads.emplace_back(thread_func); 67 68 // use the barrier to make sure all threads start before we stop 69 pseudo_barrier_wait(barrier); 70 std::raise(SIGINT); 71 72 // allow the threads to work 73 can_work.store(true); 74 75 for (std::thread &thread : threads) 76 thread.join(); 77 return 0; 78 } 79