赞
踩
1.用户通过键盘Ctrl +C,产生2号信号SIGINT(信号被创建)
2.信号产生但是没有被处理(未决)
-在内核中将所有的没有被处理的信号存储在一个集合中(未决信号集)
- SIGINT信号状态被存储在第二个标志位上
-这个标志位的值为0,说明信号不是未决状态
-这个标志位的值为1,说明信号处于未决状态
3.这个未决状态的信号需要被处理,在处理之前需要和另一个信号集(阻塞信号集)进行比较
-阻塞信号集默认为0,不会阻塞任何信号,如果需要阻塞某些信号,需要调用某些api
-如果阻塞信号集对应信号为0:则信号被处理
-如果阻塞信号集对应信号为1:则信号阻塞继续处于未决状态,直到阻塞信号集变为0.
/* #include <signal.h> int sigemptyset(sigset_t *set); -功能:清空信号集中的数据,将信号集中的所有的标0记位置为 -参数: -set:传出参数,需要操作的信号集 -返回值: 成功:0 失败:-1 int sigfillset(sigset_t *set); -功能:将信号集中的所有的标记位置为1 -参数: -set:传出参数,需要操作的信号集 -返回值: 成功:0 失败:-1 int sigaddset(sigset_t *set, int signum); -功能:设置信号集(set)中的signum位为1(阻塞信号) -参数: -set:传出参数,需要操作的信号集 -signum:信号位 -返回值: 成功:0 失败:-1 int sigdelset(sigset_t *set, int signum); -功能:设置信号集(set)中的signum位为0(不阻塞信号) -参数: -set:传出参数,需要操作的信号集 -signum:信号位 -返回值: 成功:0 失败:-1 int sigismember(const sigset_t *set, int signum); -功能:判断signum是否阻塞 -参数: set:信号集 signum:信号 -返回值: 1:signum被阻塞 0:signum不阻塞 -1:错误,调用失败 以上函数都是对自定义的信号集进行操作,以下可以对系统的信号集进行操作: int sigprocmask(int how, const sigset_t *set, sigset_t *oldset); int sigpending(sigset_t *set); */ #include <stdio.h> #include <signal.h> int main(){ //创建信号集 sigset_t set; //判断SIGINT是否阻塞 int isclock = sigismember(&set, SIGINT); printf("判断初始:isclock = %d \n", isclock); //清空信号集内容int sigemptyset(sigset_t *set) int ret = sigemptyset(&set); if(ret == -1){ perror("sigemptyset"); return -1; } //再次判断SIGINT是否阻塞 isclock = sigismember(&set, SIGINT); printf("清空: isclock = %d \n", isclock); //设置为阻塞1 ret = sigaddset(&set, SIGINT); if(ret == -1){ perror("sigaddset"); return -1; } //再次判断SIGINT是否阻塞 isclock = sigismember(&set, SIGINT); printf("设置为阻塞:isclock = %d \n", isclock); //设置不阻塞 ret = sigdelset(&set, SIGINT); if(ret == -1){ perror("sigdelset"); return -1; } //再次判断SIGINT是否阻塞 isclock = sigismember(&set, SIGINT); printf("设置为不阻塞:isclock = %d \n", isclock); return 0; }
添加set阻塞:
SIG_BLOCK:
内核mask: 10010
阻塞set : 00101
|: ------------
mask|set: 10111 //添加了set阻塞
=================================
解除set阻塞:
SIG_UNBLOCK:
~set: 11010
mask: 10010
mask &= ~set: ----------------------
10010 //回到最初mask
/* int sigprocmask(int how, const sigset_t *set, sigset_t *oldset); -功能:将自定义信号集中的数据设置到内核中(设置阻塞、解除阻塞、替换) -参数: -how: 如何对内核阻塞信号集进行处理 -SIG_BLOCK: 将用户设置的阻塞信号添加到内核中,内核中原来的数据不变 mask | set -SIG_UNBLOCK: 根据用户设置的数据,岁内核中的数据进行解除阻塞 mask &= ~set -SIG_SETMASK: 覆盖内核中原来的值 -set:已经初始好的用户自定义的信号集 -oldset: 保存设置之前的内核中的阻塞信号状态,可以是NULL -返回值: 成功: 0 失败: -1 并返回错误号(EFAULT | EINVAL) int sigpending(sigset_t *set); -功能: 获取内核中的未决信号集 -参数: set: 传出参数,保存内核中的未决信号集 -返回值: 成功: 0 失败: -1 */ //编写程序,把所有的常规信号(1-31)的未决信号打印(0: 非阻塞、1:阻塞) //设置某些信号是阻塞的,通过键盘产生这些信号 #include <stdio.h> #include <signal.h> #include <unistd.h> int main(){ //设置2(SIGINT(ctrl+c))/3(SIGQUIT(ctrl+\))号信号阻塞 sigset_t set; int ret = sigemptyset(&set); if(ret == -1){ perror("sigemptyset"); return -1; } //将2/3号信号置为1 ret =sigaddset(&set, SIGINT); if(ret == -1){ perror("sigaddset SIGINT"); return -1; } ret =sigaddset(&set, SIGQUIT); if(ret == -1){ perror("sigaddset SIGQUIT"); return -1; } //修改内核中的阻塞信号集 ret = sigprocmask(SIG_BLOCK, &set, NULL); if(ret == -1){ perror("sigprocmask"); return -1; } int j=100; while(--j){ //获取当前的未决信号集数据 sigset_t penSet; ret = sigemptyset(&penSet); if(ret == -1){ perror("sigemptyset penSet"); return -1; } ret = sigpending(&penSet); if(ret == -1){ perror("sigpending"); return -1; } //遍历前32位 for(int i=1; i<=32; i++){ if(sigismember(&penSet, i) == 1){ printf("1"); }else if(sigismember(&penSet, i) == 0){ printf("0"); }else{ perror("sigismember"); return -1; } } printf("\n"); sleep(1); if(i%10 == 0){ //解除阻塞 printf("j = %d\n", j); sigprocmask(SIG_UNBLOCK, &set, NULL); } } return 0; }
/* #include <signal.h> int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact); -功能:检查或者改变信号的处理,信号捕捉 -参数: -signum:信号编号或宏值(推荐) -act: 捕捉信号好的处理动作 -oldact:上一次信号捕捉相关设置,一般不使用(NULL) -返回值: -成功:0 -失败:-1 struct sigaction { void (*sa_handler)(int);//函数指针,信号捕捉后的处理函数 void (*sa_sigaction)(int, siginfo_t *, void *); //不常用 sigset_t sa_mask;//设置的临时阻塞信号集,在信号捕捉函数执行过程中,临时阻塞某些信号,执行完成后就不再起作用 int sa_flags;//使用哪一个信号处理(0:sa_handler | SA_SIGINFO:sa_sigaction) void (*sa_restorer)(void);//已弃用(NULL) }; */ /* #include <signal.h> typedef void (*sighandler_t)(int); sighandler_t signal(int signum, sighandler_t handler); -功能:设置某个信号的捕捉行为 -参数: -signum:要捕捉的信号 -handler:如何处理 -SIG_IGN:忽略信号 -SIG_DFL:使用默认的信号,无作为 -回调函数:内核调用 -返回值: -成功:返回上一次注册信号处理的地址,第一次调用返回NULL -失败:返回SIG_ERR,设置错误号 SIGKILL 和 SIGSTOP 不能被捕捉和hulue */ #include <stdio.h> #include <sys/time.h> #include <signal.h> #include <unistd.h> #include <stdlib.h> void myalarm(int num){ printf("捕捉到了信号:%d \n", num); printf("*************\n"); } //五秒后每隔三秒定时 int main(){ struct sigaction act; act.sa_flags = 0; act.sa_handler = myalarm; sigemptyset(&act.sa_mask);//清空临时阻塞信号集 //注册捕捉信号 sigaction(SIGALRM, &act, NULL); struct itimerval new_value; //设置间隔时间 new_value.it_interval.tv_sec = 2;//间隔时间 new_value.it_interval.tv_usec = 0; //设置延迟时间 new_value.it_value.tv_sec = 3;//第一次定时也会发送信号 new_value.it_value.tv_usec = 0; int ret = setitimer(ITIMER_REAL, &new_value, NULL);//非阻塞 printf("定时器开始了。。。。。。\n"); if(ret == -1){ perror("setitimer"); return -1; } int i = 1; while(1){ printf("i = %d \n", i++); sleep(1); } return 0; }
/* SIGCHLD信号产生的是三个条件: -1:子进程结束 -2: 子进程暂停(收到SIGSTOP信号暂停) -3:子进程继续运行(处于停止态,收到SIGCONT后唤醒) 以上三种情况都会给父进程发送该信号,父进程默认忽略该信号 可以用SIGCHLD解决僵尸进程问题 */ #include <stdio.h> #include <signal.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/wait.h> void myFunc(int num){ printf("捕捉到了信号: %d \n", num); //回收子进程的pcb资源 while(1){ int ret = waitpid(-1, NULL, WNOHANG); if(ret > 0){ printf("%d 已被回收\n", ret); }else if(ret == 0){ //还有子进程活着 break; }else{ //无子进程 break; } } } int main(){ //提前设置好阻塞信号集,阻塞SIGCHLD,因为有可能子进程已经结束了父进程还没有注册阻塞信号集 sigset_t set; sigemptyset(&set); sigaddset(&set, SIGCHLD); sigprocmask(SIG_BLOCK, &set, NULL); //创建爱你子进程 pid_t pid; for(int i=0; i<20; i++){ pid = fork(); if(pid == 0){ break;//不让子进程再创建子进程 } } if(pid > 0){ //P //捕捉子进程死亡时发送的SIGCHLD信号,然后回收子进程的pid struct sigaction act; act.sa_flags = 0; act.sa_handler = myFunc; sigemptyset(&act.sa_mask); sigaction(SIGCHLD, &act, NULL); //注册完信号捕捉之后 解除阻塞 sigprocmask(SIG_UNBLOCK, &set, NULL); while(1){ printf("parent process pid = %d \n", getpid()); sleep(2); } }else if(pid == 0){ //C printf("child process pid = %d \n", getpid()); //wait()/waitpid(-1, &wstatus, 0) }else{ perror("fork"); return -1; } return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。