linux系统编程之信号(四)
今天继续探讨信号相关的东东,话不多说,正入正题:
#include <unistd.h> #include <sys/stat.h> #include <sys/wait.h> #include <sys/types.h> #include <fcntl.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <signal.h> #define ERR_EXIT(m) do { perror(m); exit(EXIT_FAILURE); } while(0) void handler(int sig); void printsigset(sigset_t *set)//打印出信号集的状态,其中参数set为未诀状态的信号集 { int i; for (i=1; i<NSIG; ++i)//NSIG表示信号的最大值,也就是等于64 { if (sigismember(set, i))//说明是未诀状态的信号 putchar(‘1‘); else putchar(‘0‘);//说明不是未诀状态的信号 } printf("\n"); } int main(int argc, char *argv[]) { sigset_t pset; for (;;) { sigpending(&pset);//该函数是获取进程当中未诀状态的信号集 ,保存在pset当中 printsigset(&pset);//打印信号集的状态,看有没有未诀状态的信号产生 sleep(1); } return 0; }
【说明】:sigpending是用来获取进程中所有的未诀信号集:
这时看一下运行效果:
可以发现,当前状态没有未诀的信号,因为还没有被阻塞的信号过,信号也没有产生过,所以不可能有未诀的状态。
这时,我们来安装一个SIGINT信号:
#include <unistd.h> #include <sys/stat.h> #include <sys/wait.h> #include <sys/types.h> #include <fcntl.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <signal.h> #define ERR_EXIT(m) do { perror(m); exit(EXIT_FAILURE); } while(0) void handler(int sig); void printsigset(sigset_t *set) { int i; for (i=1; i<NSIG; ++i) { if (sigismember(set, i)) putchar(‘1‘); else putchar(‘0‘); } printf("\n"); } int main(int argc, char *argv[]) { sigset_t pset; if (signal(SIGINT, handler) == SIG_ERR)//安装一个SIGINT信号 ERR_EXIT("signal error"); for (;;) { sigpending(&pset); printsigset(&pset); sleep(1); } return 0; } void handler(int sig) { printf("recv a sig=%d\n", sig); }
这时再看下效果:
从结果来看,信号被直接递达了,所以这次也没有看到有1的未诀状态的信号,因为信号必须被阻塞才会出现未诀状态,所以接下来将SIGINT信号利用上面介绍到的函数来将其阻塞掉:
#include <unistd.h> #include <sys/stat.h> #include <sys/wait.h> #include <sys/types.h> #include <fcntl.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <signal.h> #define ERR_EXIT(m) do { perror(m); exit(EXIT_FAILURE); } while(0) void handler(int sig); void printsigset(sigset_t *set) { int i; for (i=1; i<NSIG; ++i) { if (sigismember(set, i)) putchar(‘1‘); else putchar(‘0‘); } printf("\n"); } int main(int argc, char *argv[]) { sigset_t pset; sigset_t bset; sigemptyset(&bset);//将信号集清0 sigaddset(&bset, SIGINT);//将SIGINT所对应的位置1 if (signal(SIGINT, handler) == SIG_ERR) ERR_EXIT("signal error"); sigprocmask(SIG_BLOCK, &bset, NULL);//更改进程中的信号屏蔽字,其中第三个参数传NULL,因为不关心它原来的信号屏蔽字 for (;;) { sigpending(&pset); printsigset(&pset); sleep(1); } return 0; } void handler(int sig) { printf("recv a sig=%d\n", sig); }
编译运行:
从结果来看,将SIGINT信号来了,由于添加到了信号屏蔽字为1,所以会被阻塞掉,并且可以看到SIGINT对应的位也打印为1了。
【说明】:SIGINT对应的位是指:
下面,我们做一件事情,就是当我们按下ctrl+\解除阻塞,这样处于未诀状态的信号就会被递达,则对应的未诀状态位也会还原成0,具体代码如下:
#include <unistd.h> #include <sys/stat.h> #include <sys/wait.h> #include <sys/types.h> #include <fcntl.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <signal.h> #define ERR_EXIT(m) do { perror(m); exit(EXIT_FAILURE); } while(0) void handler(int sig); void printsigset(sigset_t *set) { int i; for (i=1; i<NSIG; ++i) { if (sigismember(set, i)) putchar(‘1‘); else putchar(‘0‘); } printf("\n"); } int main(int argc, char *argv[]) { sigset_t pset; sigset_t bset; sigemptyset(&bset); sigaddset(&bset, SIGINT); if (signal(SIGINT, handler) == SIG_ERR) ERR_EXIT("signal error"); if (signal(SIGQUIT, handler) == SIG_ERR)//注册一个ctrl+c信号 ERR_EXIT("signal error"); sigprocmask(SIG_BLOCK, &bset, NULL); for (;;) { sigpending(&pset); printsigset(&pset); sleep(1); } return 0; } void handler(int sig) { if (sig == SIGINT) printf("recv a sig=%d\n", sig); else if (sig == SIGQUIT) { sigset_t uset;//当按下ctrl+\时,则对SIGINT信号解除阻塞 sigemptyset(&uset); sigaddset(&uset, SIGINT); sigprocmask(SIG_UNBLOCK, &uset, NULL); } }
编译运行:
从中可以看到,当我们按下ctrl+\时,并没有退出,而是解除了阻塞,所以对应的SIGINT位也变为0了。
另外,看下这种情况:
多次按了ctrl+c,可在按ctrl+\解除阻塞时,只响应了一次信号处理函数,这也由于SIGINT是不可靠信号,不支持排队。
另外,由于我们捕获了ctrl+\信号,所以没办法退出这个进程了,那怎么办呢,可以利用shell命令将其强制杀掉如下:
好了,今天学的东西可能有些生涩,需好好消化,下节再见!
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。