a.cpp
#include <sys/types.h>
#include <signal.h>
#include <pthread.h>
#include <unistd.h>
#include <cstdio>
#include <cstring>
#include <mutex>
#include <thread>
#include <map>
#include <random>
typedef void(*Handler_func)(int);
void sig_handler(int) {
}
int check_signal() {
sigset_t ss;
sigemptyset(&ss);
sigaddset(&ss, SIGTERM);
sigaddset(&ss, SIGUSR1);
timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = 0;
int sig = sigtimedwait(&ss, nullptr, &ts);
if (sig > 0) {
return sig;
} else {
if (errno != EAGAIN) {
char buf[1024];
char *bufp = strerror_r(errno, buf, 1024);
printf("sigtimedwait fail. %s\n", bufp);
return -1;
}
}
return 0;
}
int set_sigprocmask() {
sigset_t newss;
sigemptyset(&newss);
sigaddset(&newss, SIGCHLD);
sigaddset(&newss, SIGUSR1);
sigaddset(&newss, SIGALRM);
sigaddset(&newss, SIGHUP);
sigaddset(&newss, SIGINT);
sigaddset(&newss, SIGQUIT);
sigaddset(&newss, SIGTERM);
if (sigprocmask(SIG_BLOCK, &newss, nullptr)) {
return 1;
} else {
return 0;
}
}
int set_sigaction(int sig, Handler_func func) {
struct sigaction sa;
memset(&sa, 0, sizeof(struct sigaction));
sa.sa_handler = func;
sigemptyset(&sa.sa_mask);
if (sigaction(sig, &sa, nullptr)) {
return 1;
} else {
return 0;
}
}
int set_sigaction_ign(int sig) {
struct sigaction sa;
memset(&sa, 0, sizeof(struct sigaction));
sa.sa_handler = SIG_IGN;
sigemptyset(&sa.sa_mask);
if (sigaction(sig, &sa, nullptr)) {
return 1;
} else {
return 0;
}
}
int init_signal() {
set_sigaction(SIGCHLD, &sig_handler);
set_sigaction(SIGUSR1, &sig_handler);
set_sigaction(SIGALRM, &sig_handler);
set_sigaction(SIGHUP, &sig_handler);
set_sigaction(SIGINT, &sig_handler);
set_sigaction(SIGQUIT, &sig_handler);
set_sigaction(SIGTERM, &sig_handler);
set_sigaction_ign(SIGPIPE);
if (set_sigprocmask()) {
return 1;
} else {
return 0;
}
}
class th_info {
public:
std::thread th;
pthread_t main_pthread_t;
};
void thread_func(std::mutex &mtx, std::map<int, th_info> &ths, int num) {
//Stops during parental production and processing
mtx.lock();
mtx.unlock();
std::random_device rd;
std::mt19937 mt(rd());
std::uniform_int_distribution<int> wait_time(1, 10);
while (!check_signal()) {
sleep(wait_time(mt));
printf("[%d]: send SIGUSR1.\n", num);
mtx.lock();
pthread_kill(ths[num].main_pthread_t, SIGUSR1);
mtx.unlock();
}
}
void main_thread(std::mutex &mtx, std::map<int, th_info> &ths) {
sigset_t ss;
sigemptyset(&ss);
sigaddset(&ss, SIGHUP);
sigaddset(&ss, SIGTERM);
sigaddset(&ss, SIGINT);
sigaddset(&ss, SIGQUIT);
sigaddset(&ss, SIGUSR1);
while (1) {
int sig;
sigwait(&ss, &sig);
if (sig == SIGUSR1) {
printf("recv SIGUSR1.\n");
} else {
printf("recv FINISH SIGNAL.\n");
break;
}
}
//Collect subthreads
mtx.lock();
for (auto &it : ths) {
pthread_kill(it.second.th.native_handle(), SIGUSR1);
}
mtx.unlock();
for (auto &it : ths) {
it.second.th.join();
}
}
void gen_thread(std::mutex &mtx, std::map<int, th_info> &ths) {
pthread_t main_pthread_t = pthread_self();
mtx.lock();
for (int i = 0; i < 3; ++i) {
std::thread th(thread_func, std::ref(mtx), std::ref(ths), i);
ths[i].th = std::move(th);
ths[i].main_pthread_t = main_pthread_t;
}
mtx.unlock();
}
int main(int, char **) {
if (init_signal()) {
printf("init_signal fail.\n");
return 1;
}
std::mutex mtx;
std::map<int, th_info> ths;
gen_thread(mtx, ths);
main_thread(mtx, ths);
return 0;
}
[root@localhost ~]# g++ --std=c++11 a.cpp -lpthread [root@localhost ~]# [root@localhost ~]# ./a.out [1]: send SIGUSR1. recv SIGUSR1. [2]: send SIGUSR1. recv SIGUSR1. [0]: send SIGUSR1. recv SIGUSR1. [1]: send SIGUSR1. recv SIGUSR1. [2]: send SIGUSR1. recv SIGUSR1. [2]: send SIGUSR1. recv SIGUSR1. [0]: send SIGUSR1. recv SIGUSR1. ^Crecv FINISH SIGNAL. [1]: send SIGUSR1. [2]: send SIGUSR1. [0]: send SIGUSR1. [root@localhost ~]#
Before spawning a thread, run pthread_self () on the main thread and You can save it.
If you want to notify the main thread on the sub thread side, pthread_kill(main_pthread_t, SIGUSR1); You can notify it like this.
After setting the handler in advance for signal related settings If you don't block it, it won't work.
At the time of threading, use sigwait etc. as much as possible, Prevent the handler from working. (So, at the end of the program, the subthread is just sleeping in sleep, These will not be interrupted by interrupt processing, and will end after waiting for the number of seconds passed.)
If you make the code work for the time being, it will be somewhat long ... Hmm.
2015/12/10 postscript
Looking at the operation, when I send a signal to the main thread, Other threads are also receiving ...
Only the main thread needs to catch the signal with sigwait, When other threads are also waiting with sigwait, Both the main thread and other threads are returned from sigwait ...
Hmmm, subthread-> decide the signal to send to the main thread separately, It's a solution if you don't wait for the signal on the subthread side. ..
I wonder if it's smarter and I can't send a signal only to the main thread.
I saved the main thread pthread_t to send a signal with pthread_kill, After all, it seems to be equivalent to the process of kill (pid of the main thread, SIGUSR1) ;.
Hmm.
Recommended Posts