C 如何创建用于信号处理的线程,并在接收到信号后退出进程?
我编写了以下代码来处理单独线程中的信号,以强制清理一些资源并退出整个过程 下面是关于下面代码的简要说明C 如何创建用于信号处理的线程,并在接收到信号后退出进程?,c,linux,signals,C,Linux,Signals,我编写了以下代码来处理单独线程中的信号,以强制清理一些资源并退出整个过程 下面是关于下面代码的简要说明 当接收到信号时,setvolatile sig_atomic_t sig_set_flag=1内部信号处理程序 在信号处理器线程中,检查循环中的sig set标志值 if(sig\u set\u flag==1)从信号处理器线程发送类似“我要下楼”的通知,并调用退出(0)来自线程 进程中的任何线程都可以接收信号。所以我设置了全局变量 我有两个问题 1) 这个实现很好吗?或者我必须阻止主线程
- 当接收到信号时,setvolatile sig_atomic_t sig_set_flag=1内部信号处理程序
- 在信号处理器线程中,检查循环中的sig set标志值
- if(sig\u set\u flag==1)从信号处理器线程发送类似“我要下楼”的通知,并调用退出(0)来自线程
#include <stdio.h>
#include <signal.h>
#include <pthread.h>
#include <stdatomic.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
/*
* Set this variable if any signal is received
*/
volatile sig_atomic_t sig_set_flag = 0;
pthread_mutex_t cleanup_mutex;
/*
* Resource cleanup function.
*/
int cleaup_resources() {
pthread_mutex_lock(&cleanup_mutex);
/*
* Send notification to all the clients.
* Delete all the temp files
*/
printf("Notified to clients.Exiting process\n");
pthread_mutex_unlock(&cleanup_mutex);
return 0;
}
/*
* Signal handler thread
*/
void sig_term_handler(int sig_num) {
sig_set_flag = sig_num;
}
/*
* Signal handler thread routine
*/
void *signal_handler_thread(void * args) {
while(1) {
if(sig_set_flag != 0) {
printf("%s : Signal flag is set for sig_no %d\n",__func__,sig_set_flag);
cleaup_resources();
break;
}
usleep(5);
}
exit(0);
}
int main()
{
int loop_count,status;
pthread_t tid;
pid_t pid;
struct sigaction sig;
sig.sa_handler = &sig_term_handler;
sig.sa_flags = 0;
sigaction(SIGTERM, &sig, NULL);
/*
* Spawn a thread to monitor signals.
* If signal received, Exit the process.
*/
pthread_create(&tid, NULL, signal_handler_thread, NULL);
while(1) {
printf("Some time consuming task in progress... PID = %d\n",getpid());
pid = fork();
if(pid == 0) {
sleep(100);
return 0;
} else {
waitpid(pid, &status, 0);
loop_count++;
if( loop_count>=10)
break;
}
}
cleaup_resources();
exit(0);
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
/*
*如果收到任何信号,则设置此变量
*/
易失性信号原子信号集标志=0;
pthread_mutex_t cleanup_mutex;
/*
*资源清理功能。
*/
int cleaup_资源(){
pthread_mutex_lock(&cleanup_mutex);
/*
*向所有客户端发送通知。
*删除所有临时文件
*/
printf(“已通知客户端。正在退出进程\n”);
pthread_mutex_unlock(&cleanup_mutex);
返回0;
}
/*
*信号处理器线程
*/
无效符号项处理程序(int sig_num){
sig_set_flag=sig_num;
}
/*
*信号处理器线程例程
*/
void*信号处理程序线程(void*args){
而(1){
如果(信号设置标志!=0){
printf(“%s:信号标志已为信号编号%d\n设置”,\uuuuu func\uuuuu,信号设置\u标志);
cleaup_resources();
打破
}
usleep(5);
}
出口(0);
}
int main()
{
int loop_计数、状态;
pthread_t tid;
pid_t pid;
结构sig动作sig;
sig.sa_handler=&sig_term_handler;
sig.sa_标志=0;
sigation(SIGTERM,&sig,NULL);
/*
*生成一个线程来监视信号。
*如果收到信号,则退出该过程。
*/
pthread\u create(&tid,NULL,signal\u handler\u thread,NULL);
而(1){
printf(“正在进行一些耗时的任务…PID=%d\n”,getpid());
pid=fork();
如果(pid==0){
睡眠(100);
返回0;
}否则{
waitpid(pid和status,0);
循环计数++;
如果(循环计数>=10)
打破
}
}
cleaup_resources();
出口(0);
}
注意:我知道信号会中断一些系统调用,并且会设置EINTR。不幸的是,某些系统调用(即waitpid()不会被中断。所以我产生了一个线程来处理这个场景。1)您的实现似乎是正确的signal()
和sigaction()
为整个进程注册一个处理函数,因此在主线程或派生线程中调用它们并不重要
2) 要在主线程中阻止信号并在线程中处理它,必须使用sigwait()
或sigwaitinfo()
设计处理程序线程,而不是处理程序函数。因此线程将等待信号,程序执行不会中断
在这种情况下,必须在所有线程(包括主线程)中阻止进程范围的信号。如果未被阻止,信号将在程序上具有默认行为
必须使用pthread\u sigmask()
来阻止一个或多个信号。阻止SIGTERM的代码示例:
sigset_t set;
sigemptyset(&set);
sigaddset(&set,SIGTERM);
pthread_sigmask(SIG_BLOCK,&set,NULL);
创建线程时,它会继承创建者线程的阻塞信号
我修改了您的代码,向您展示了如何使用sigwaitinfo()
和pthread\u sigmask()
:
#包括
#包括
#包括
#包括
#包括
#包括
#包括
pthread_mutex_t cleanup_mutex;
/*
*资源清理功能。
*/
int cleaup_资源(){
pthread_mutex_lock(&cleanup_mutex);
/*
*向所有客户端发送通知。
*删除所有临时文件
*/
printf(“已通知客户端。正在退出进程\n”);
pthread_mutex_unlock(&cleanup_mutex);
返回0;
}
/*
*信号处理器线程例程
*/
void*信号处理程序线程(void*args){
sigset\u t集;
sigpemptyset(&set);
sigaddset(&set,SIGINT);
siginfo_t info;
而(1){
sigwaitinfo(设置和信息(&S);
if(info.si_signo==SIGINT){
printf(“\n收到的签名\n”);
cleaup_resources();
出口(0);
}
}
}
int main()
{
int loop_计数、状态;
pthread_t tid;
pid_t pid;
sigset\u t集;
sigpemptyset(&set);
sigaddset(&set,SIGINT);
pthread_sigmask(SIG_块,&set,NULL);
//新线程将继承被阻止的线程
//来自创建它的线程的信号:
pthread\u create(&tid,NULL,signal\u handler\u thread,NULL);
而(1){
printf(“正在进行一些耗时的任务…PID=%d\n”,getpid());
pid=fork();
如果(pid==0){
睡眠(100);
返回0;
}否则{
waitpid(pid和status,0);
循环计数++;
如果(循环计数>=10)
打破
}
}
cleaup_resources();
出口(0);
}
另外,请注意
fork()
,根据我所做的测试,子进程将继承阻塞的信号。能否避免显式清理资源?我问这个问题是因为这总是一件痛苦的事情,需要持续的测试/调试/验证,而且通常是可以避免的,例如“删除所有临时文件”-你不能在启动时删除它们吗?毕竟,在“kill-9”或电源故障时,您的清理尝试将失败。对不起,您是说waitpid
不能被信号中断吗?EINTR是一种记录在案的错误情况,如果所有信号的PID不会被中断。(即)SIGHUP不会打断waitpid。@NaveenKumar,我们是bi
#include <stdio.h>
#include <signal.h>
#include <pthread.h>
#include <stdatomic.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
pthread_mutex_t cleanup_mutex;
/*
* Resource cleanup function.
*/
int cleaup_resources() {
pthread_mutex_lock(&cleanup_mutex);
/*
* Send notification to all the clients.
* Delete all the temp files
*/
printf("Notified to clients.Exiting process\n");
pthread_mutex_unlock(&cleanup_mutex);
return 0;
}
/*
* Signal handler thread routine
*/
void *signal_handler_thread(void * args) {
sigset_t set;
sigemptyset(&set);
sigaddset(&set,SIGINT);
siginfo_t info;
while(1) {
sigwaitinfo(&set,&info);
if(info.si_signo == SIGINT){
printf("\nSIGINT received\n");
cleaup_resources();
exit(0);
}
}
}
int main()
{
int loop_count,status;
pthread_t tid;
pid_t pid;
sigset_t set;
sigemptyset(&set);
sigaddset(&set,SIGINT);
pthread_sigmask(SIG_BLOCK,&set,NULL);
// The new thread will inherit the blocked
// signals from the thread that create it:
pthread_create(&tid, NULL, signal_handler_thread, NULL);
while(1) {
printf("Some time consuming task in progress... PID = %d\n",getpid());
pid = fork();
if(pid == 0) {
sleep(100);
return 0;
} else {
waitpid(pid, &status, 0);
loop_count++;
if( loop_count>=10)
break;
}
}
cleaup_resources();
exit(0);
}