1 #include "pseudo_barrier.h"
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;
20 static void sigint_handler(int signo
) {}
22 static 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());
28 static void thread_func() {
29 // this ensures that all threads start before we stop
30 pseudo_barrier_wait(barrier
);
32 // wait till the main thread indicates that we can go
33 // (note: using a mutex here causes hang on FreeBSD when another thread
35 while (!can_work
.load())
36 std::this_thread::sleep_for(std::chrono::milliseconds(50));
38 // the mutex guarantees that two writes don't get interspersed
40 std::lock_guard
<std::mutex
> lock
{print_mutex
};
41 std::printf("thread %" PRIx64
" running\n", get_thread_id());
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));
52 // if we didn't get signaled, terminate the program explicitly.
56 int main(int argc
, char **argv
) {
57 int num
= atoi(argv
[1]);
59 pseudo_barrier_init(barrier
, num
+ 1);
61 signal(SIGINT
, sigint_handler
);
62 signal(SIGUSR1
, sigusr1_handler
);
64 std::vector
<std::thread
> threads
;
65 for (int i
= 0; i
< num
; ++i
)
66 threads
.emplace_back(thread_func
);
68 // use the barrier to make sure all threads start before we stop
69 pseudo_barrier_wait(barrier
);
72 // allow the threads to work
75 for (std::thread
&thread
: threads
)