目录
掌握:信号集和信号屏蔽
应用:
有时候不希望在接到信号时就立即停止当前执行,去处理信号,同时也不希望忽略该信号,而是延
时一段时间去调用信号处理函数。这种情况可以通过阻塞信号实现。
信号的阻塞概念:
信号的”阻塞“是一个开关动作,指的是阻止信号被处理,但不是阻止信号产生。
信号的状态:
信号递达(Delivery ):实际信号执行的处理过程(3种状态:忽略,执行默认动作,捕获)
信号未决(Pending):从产生到递达之间的状态(挂起)
下图表示了,每一个任务控制块都有一个挂起信号集(可读)和信号屏蔽字(可写可读)。信号屏蔽置1,代表忽略该信号的到来

sigset_t set;
自定义信号集。 是一个 64bit 128bit的数组。
sigemptyset(sigset_t *set);
代表接收所有信号
sigfillset(sigset_t *set);
接收全部信号
sigaddset(sigset_t *set, int signum);
接收某一个位的信号
sigdelset(sigset_t *set, int signum);
屏蔽某一个位的信号
sigismember(const sigset_t *set,int signum);
- #include
- int sigprocmask( int how, const sigset_t *restrict set, sigset_t *restrict oset );
参数说明:
how:表示如何修改信号屏蔽字的标志,可取以下值:
SIG_BLOCK:将set中指定的信号添加到当前信号屏蔽字中。SIG_UNBLOCK:将set中指定的信号从当前信号屏蔽字中移除。SIG_SETMASK:用set中指定的信号集替换当前信号屏蔽字。set:指向要修改的新的信号屏蔽字的指针。如果为NULL,则不会修改信号屏蔽字。oset:用于保存旧的信号屏蔽字的指针。如果为NULL,则不会保存旧的信号屏蔽字。函数返回值:
oset中(如果oset不为NULL)。errno来指示错误的原因。该函数用于在多线程编程、信号处理等场景中控制信号的屏蔽,以保证信号处理的正确性和可靠性。
示例:
- #include
- #include
- #include
- #include
-
-
- void handle(int sig){
-
- printf("I get sig=%d\n",sig);
-
- }
-
- int main(){
-
- struct sigaction act;
- act.sa_handler = handle; //注册回调函数
- sigemptyset(&act.sa_mask); //清空信号集,代表接收所有信号
- act.sa_flags = 0; //通过将其设置为0,表示不使用任何额外的标志位,即默认行为。
- sigaction(SIGINT,&act,NULL); //信号捕获
- sigset_t set; //定义信号集
- sigemptyset(&set); //清空信号集
- sigaddset(&set,SIGINT); //SIGINT,屏蔽SIGINT信号
-
- sigprocmask(SIG_BLOCK,&set,NULL); //ctrl+c的信号阻塞,接收不到
- sleep(5);
- sigprocmask(SIG_UNBLOCK,&set,NULL); //取消信号阻塞
-
- while(1){
- sleep(1);
- }
-
- }
执行效果 :

int pause(void);
进程一直阻塞,直到被信号中断,返回值:-1 并设置errno为EINTR
函数行为:
-1 如果信号的默认处理动作是终止进程,则进程终止,pause函数没有机会返回。
-2 如果信号的默认处理动作是忽略,进程继续处于挂起状态,pause函数不返回
-3 如果信号的处理动作是捕捉,则调用完信号处理函数之后,pause返回-1。
-4 pause收到的信号如果被屏蔽,那么pause就不能被唤醒
示例:pause阻塞效果
- #include
- #include
- #include
- #include
-
-
- int main(int argc, char * argv[])
- {
- pause();
- printf("after pause\n");
- }
-
- //运行后结果程序阻塞中,未打印after pause,按ctrl+c或ctrl+\结束
- linux@linux:~/Desktop$ ./pause
-
示例:pause阻塞效果2
- #include
- #include
- #include
- #include
-
- void handle(int sig)
- {
- printf("Handle:I get sig=%d\n",sig);
- }
-
- int main(int argc, char * argv[])
- {
- struct sigaction act;
- act.sa_handler = handle;
- act.sa_flags = 0;
- sigemptyset(&act.sa_mask);
- sigaction(SIGINT,&act,NULL);
-
- pause();
- printf("after pause\n");
- }
-
- //运行结果,未恢复至原处理函数的执行效果
- linux@linux:~/Desktop$ ./pause
- ^CHandle:I get sig=2
- after pause
- linux@linux:~/Desktop$
示例:pause阻塞效果3 ,实现一个等待信号的任务
- #include
- #include
- #include
- #include
-
- void handle(int sig)
- {
- printf("Handle:I get sig=%d\n",sig);
- }
-
- void mytask()
- {
- printf("mytask:start\n");
- sleep(3);
- printf("mytask:end\n");
- }
-
- int main(int argc, char * argv[])
- {
- struct sigaction act;
- act.sa_handler = handle;
- act.sa_flags = 0;
- sigemptyset(&act.sa_mask);
- sigaction(SIGINT,&act,NULL);
-
- pause();
- while(1)
- {
- mytask();
- pause(); //每次等待信号到来再执行mytask
- }
- printf("After pause\n");
- }
-
- //运行结果
- linux@linux:~/Desktop$ ./pause
- ^CHandle:I get sig=2
- mytask:start
- mytask:end
- ^CHandle:I get sig=2
- mytask:start
- mytask:end
- ^CHandle:I get sig=2
- mytask:start
- mytask:end
-
使用kill 发送SIGHUP信号关闭
示例:pause阻塞效果4 ,实现一个等待多个信号的任务(SIGINT,SIGHUP)
- #include
- #include
- #include
- #include
-
- void handle(int sig)
- {
- printf("Handle:I get sig=%d\n",sig);
- }
-
- void mytask()
- {
- printf("mytask:start\n");
- sleep(3);
- printf("mytask:end\n");
- }
-
- int main(int argc, char * argv[])
- {
- struct sigaction act;
- act.sa_handler = handle;
- act.sa_flags = 0;
- sigemptyset(&act.sa_mask);
- sigaction(SIGINT,&act,NULL);
- sigaction(SIGHUP,&act,NULL);
-
- pause();
- while(1)
- {
- mytask();
- pause();
- }
- printf("After pause\n");
- }
按ctrl+c,或者使用kill -1发送关闭信号都可以捕获信号处理任务。

示例:使用 sigaddset,屏蔽多个信号
- #include
- #include
- #include
-
- void handle(int sig)
- {
- printf("Handle:I get sig=%d\n",sig);
- }
-
- void mytask()
- {
- printf("mytask:start\n");
- sleep(3);
- printf("mytask:end\n");
- }
-
- int main(int argc, char * argv[])
- {
- struct sigaction act;
- act.sa_handler = handle;
- act.sa_flags = 0;
- sigemptyset(&act.sa_mask);
- sigaction(SIGINT,&act,NULL);
- sigaction(SIGHUP,&act,NULL);
-
- sigset_t set;
- sigaddset(&set,SIGHUP);
- sigaddset(&set,SIGINT);
-
- pause();
- while(1)
- {
- sigprocmask(SIG_BLOCK,&set,NULL);
- mytask();
- sigprocmask(SIG_UNBLOCK,&set,NULL);
- pause();
- }
- printf("After pause\n");
- }
执行效果,在任务过程中设置了信号屏蔽,此时按ctrl+c或者kill -1去发送信号,不会执行handle打印,直到任务结束后再开启接收信号,防止任务被打断

设定对信号集内的信号屏蔽并恢复。
int sigsuspend(const sigset_t *sigmask);
功能:函数用于临时更改进程的信号屏蔽字,并等待一个特定的信号到来,然后恢复原有的信号屏蔽字。和 pause 函数不同的是,它可以临时更改进程的信号屏蔽字,以便等待某个特定信号。
参数:
sigmask:希望屏蔽的信号
示例:解决任务中的信号丢失问题,sigsuspend相当于sigprocmask+pause
- #include
- #include
- #include
- #include
-
- void handle(int sig)
- {
- printf("Handle:I get sig=%d\n",sig);
- }
-
- void mytask()
- {
- printf("mytask:start\n");
- sleep(3);
- printf("mytask:end\n");
- }
-
- int main(int argc, char * argv[])
- {
- struct sigaction act;
- act.sa_handler = handle;
- act.sa_flags = 0;
- sigemptyset(&act.sa_mask);
- sigaction(SIGINT,&act,NULL);
- sigaction(SIGHUP,&act,NULL);
-
- sigset_t set;
- sigaddset(&set,SIGHUP);
- sigaddset(&set,SIGINT);
-
- sigset_t set2;
- sigemptyset(&set2); //接收所有信号
-
- pause();
- while(1)
- {
- sigprocmask(SIG_BLOCK,&set,NULL);
- mytask();
- //sigprocmask(SIG_UNBLOCK,&set,NULL);
- //pause();
- sigsuspend(&set2);
- }
- printf("After pause\n");
- }
运行结果
- linux@linux:~/Desktop$ ./pause
- ^CHandle:I get sig=2 //1次CTRL+C
- mytask:start
- mytask:end
- ^CHandle:I get sig=2 //1次CTRL+C
- mytask:start
- mytask:end
- ^CHandle:I get sig=2 //1次CTRL+C
- mytask:start
- ^Cmytask:end //任务中途的1次CTRL+C
- Handle:I get sig=2 //也被获取到并执行了
- mytask:start
- mytask:end
实现信号回收子进程程序
提示:SIGCHLD 是一个用于处理子进程状态变化的信号。当一个子进程终止或停止时,它的父进程会收到 SIGCHLD 信号。
- #include
- #include
- #include
- #include
- #include
-
- void handle(int sig)
- {
- wait(NULL);
- printf("Get sig =%d\n",sig);
- }
-
- int main(int argc, char* argv[])
- {
- pid_t pid;
- struct sigaction act;
-
- act.sa_handler = handle;
- act.sa_flags = 0;
- sigemptyset(&act.sa_mask);
-
- pid = fork();
-
- if(pid > 0)
- {
- printf("father process\n");
- sigaction(SIGCHLD,&act,NULL);
- }
- else if(pid == 0)
- {
- printf("childe process\n");
- sleep(5);
- exit(0);
- }
- else
- {
- perror("fork");
- return 0;
- }
-
- while(1)
- {
- sleep(1);
- }
-
- return 0;
- }
运行结果:5s后子进程退出,没有产生僵尸进程。
