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) {
//Arrêts pendant la production et le traitement des parents
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;
}
}
//Collecter les sous-threads
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 ~]#
Exécutez pthread_self () sur le thread principal avant de générer un thread Vous pouvez le sauvegarder.
Si vous souhaitez notifier le thread principal du côté du sous-thread, pthread_kill(main_pthread_t, SIGUSR1); Vous pouvez le notifier comme ça.
Après avoir défini le gestionnaire à l'avance pour les paramètres liés au signal Si vous ne le bloquez pas, cela ne fonctionnera pas.
Au moment de créer un fil, utilisez autant que possible sigwait etc., Empêchez le gestionnaire de travailler. (Donc, à la fin du programme, le sous-thread est juste en train de dormir, Ceux-ci ne seront pas supprimés en interrompant le traitement, attendez le nombre de secondes écoulées, puis terminez)
Si vous faites fonctionner le code pour le moment, ce sera un peu long ... Hmm.
Post-scriptum du 10/12/2015
Quand je regardais l'opération, quand j'ai envoyé un signal au fil principal, D'autres threads reçoivent également ...
Seul le thread principal a besoin de capter le signal avec sigwait, Lorsque d'autres threads attendent avec sigwait, Le thread principal et les autres threads sont renvoyés par sigwait ...
Hmmm, subthread-> décidez du signal à envoyer au thread principal séparément, C'est une solution si vous n'attendez pas le signal du côté du sous-thread. ..
Je me demande si c'est plus intelligent et je ne peux pas envoyer de signal uniquement au fil principal.
J'ai sauvegardé le thread principal pthread_t pour envoyer un signal avec pthread_kill, Après tout, cela semble être équivalent au processus de kill (pid du thread principal, SIGUSR1);.
Hmm.
Recommended Posts