/*************************************************************************
> File Name: signal.c
> Author:
> Mail:
> Created Time: 2015年11月21日 星期六 10时21分58秒
************************************************************************/ #include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h> void sig_handler(int num){
if(num == SIGINT){
printf("receive the SIGINT: %d\n", num);
}
else if (num == SIGQUIT){
printf("recevie the SIGQUIT: %d\n", num);
}
} int main()
{
signal(SIGINT, sig_handler);
signal(SIGQUIT, sig_handler); printf("enter to the while.\n");
while(1){
sleep(1);
} exit(0);
}

按下Ctrl+c发出中断信号,也就是发出SIGINT信号;按下Ctirl+\发出退出信号,也就是发出SIGQUIT信号;
signal函数是让程序捕获到设置的信号(第一个参数指定)的时候,去执行设置的信号处理函数(第二个参数指定);
运行结果如下:

如果想退出程序,按下Ctrl+z强制退出,但是此时输入ps,可以看到刚才运行的程序没有真正退出,这时候我们要杀死该进程;
输入:kill -9 进程号 然后再ps查看,可以看到刚才的进程已经被杀死;

实例二:

在进程控制块里面有一个64bit(0-63)的数据块,表明信号的屏蔽状态,也就是信号屏蔽状态字;每个bit表明一个信号的屏蔽状态,
比如bit1如果是1,表明SIGINT信号是被阻塞的,也就是进程收到SIGINT信号之后不会去执行,而是将该信号阻塞起来,当该信号设置为
非阻塞的时候才会去处理该SIGINT信号;
那么我们怎么设置这64个信号的阻塞和非阻塞的状态呢???内核提供了API函数,
第一步:定义sigset_t的一个变量set;
第二步:将该变量的值清零,sigemptyset(&set);
第三步:将要设置的信号添加到该信号集合中,也就是set变量中;比如:sigaddset(&set,SIGINT);
第四步:将该信号集合set注册到该进程的控制块的信号屏蔽状态字中;
int sigprocmask(int how, const sigset_t *set, sigset_t *oset);向内核里面设置信号集set;
当how是SIG_BOLCK的时候,设置该信号为阻塞;是SIG_UNBLOCK的时候,设置该信号为非阻塞;
set是刚才自定义的信号集合,oset可以返回进程控制块中的以前的信号屏蔽字的状态;(如果不需要,则设为NULL)

在进程控制块里面还有一个信号未决状态字,也是64bit,用来指明该64个信号;比如:bit1被置为了1,表明收到了SIGINT信号,但是
该信号被阻塞,没有被处理;如果bit1被置为了0,表明SIGINT可以抵达并被处理;

通过函数sigpending(&pending_set);来获得进程控制块里面的信号未决状态字的值;

/*************************************************************************
> File Name: signal.c
> Author:
> Mail:
> Created Time: 2015年11月21日 星期六 10时21分58秒
************************************************************************/ #include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h> void sig_handler(int num){
if(num == SIGINT){
printf("receive the SIGINT: %d\n", num);
}
else if (num == SIGQUIT){
printf("recevie the SIGQUIT: %d\n", num);
}
} void print_sig_set(sigset_t * set)
{
int i; for (i = 1; i <= 64; ++i){
if (sigismember(set, i)){
putchar('1');
}
else{
putchar('0');
}
}
printf("\n");
} int main()
{ sigset_t block_set;
sigset_t pending_set; sigemptyset(&block_set);
sigaddset(&block_set, SIGINT); signal(SIGINT, sig_handler);
signal(SIGQUIT, sig_handler); sigprocmask(SIG_BLOCK, &block_set, NULL); while(1){
sigpending(&pending_set);
print_sig_set(&pending_set);
sleep(1);
} exit(0);
}

运行结果每一行都是64个数字,这64个数字是进程控制块中信号未决状态字的值;可以看到,刚开始是全部都是0,当进程收到中断信号SIGINT
之后,信号未决状态字的第二个bit被置为了1,表明该信号SIGINT被置为了阻塞;当进程收到退出信号SIGQUIT之后,
信号未决状态字的第三个bit仍然是0;

实例三:

我想让收到退出信号的时候,重新设置SIGINT中断信号的阻塞状态;将SIGINT设置为非阻塞的;但是这种设置仅仅是接触阻塞,
比如如下面的运行结果可以看出:
刚开始的时候信号未决状态字的值为全0,当收到SIGINT中断的时候,bit1被置为1;当再收到SIGQUIT信号的时候,将SIGINT置为非阻塞的,
此时进程同时显示收到SIGQUIT和SIGINT信号,同时未决状态字的bit1被置为了0;当再次收到SIGINT中断的时候,bit1仍然被置为1;

/*************************************************************************
> File Name: signal.c
> Author:
> Mail:
> Created Time: 2015年11月21日 星期六 10时21分58秒
************************************************************************/ #include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h> void sig_handler(int num){
if(num == SIGINT){
printf("receive the SIGINT: %d\n", num);
}
else if (num == SIGQUIT){
printf("recevie the SIGQUIT: %d\n", num);
sigset_t new_set;
sigaddset(&new_set, SIGINT); sigprocmask(SIG_UNBLOCK, &new_set, NULL);
}
} void print_sig_set(sigset_t * set)
{
int i; for (i = 1; i <= 64; ++i){
if (sigismember(set, i)){
putchar('1');
}
else{
putchar('0');
}
}
printf("\n");
} int main()
{ sigset_t block_set;
sigset_t pending_set; sigemptyset(&block_set);
sigaddset(&block_set, SIGINT); signal(SIGINT, sig_handler);
signal(SIGQUIT, sig_handler); sigprocmask(SIG_BLOCK, &block_set, NULL); while(1){
sigpending(&pending_set);
print_sig_set(&pending_set);
sleep(1);
} exit(0);
}

实例四:

如果我想重新设置SIGINT中断信号的阻塞状态,在主函数中重新设置;实例如下:

/*************************************************************************
> File Name: signal.c
> Author:
> Mail:
> Created Time: 2015年11月21日 星期六 10时21分58秒
************************************************************************/ #include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h> void sig_handler(int num){
if(num == SIGINT){
printf("receive the SIGINT: %d\n", num);
}
else if (num == SIGQUIT){
printf("recevie the SIGQUIT: %d\n", num);
sigset_t new_set;
sigaddset(&new_set, SIGINT); sigprocmask(SIG_UNBLOCK, &new_set, NULL);
}
} void print_sig_set(sigset_t * set)
{
int i; for (i = 1; i <= 64; ++i){
if (sigismember(set, i)){
putchar('1');
}
else{
putchar('0');
}
}
printf("\n");
} int main()
{ sigset_t block_set;
sigset_t pending_set; sigemptyset(&block_set);
sigaddset(&block_set, SIGINT); signal(SIGINT, sig_handler);
signal(SIGQUIT, sig_handler); sigprocmask(SIG_BLOCK, &block_set, NULL); int time = 10;
while(time){
sigpending(&pending_set);
print_sig_set(&pending_set);
sleep(1);
time--;
}
printf("first sleep is over.\n"); sigprocmask(SIG_UNBLOCK, &block_set, NULL);
while(1){
sigpending(&pending_set);
print_sig_set(&pending_set);
sleep(1);
} exit(0);
}

从运行结果可以看出,前十秒的情况和实例三一样;当输出first sleep is over.表明前十秒结束,然后将SIGINT中断信号设置为非阻塞状态,
此后的结果表明,每次收到中断信号之后就直接处理,而不是阻塞起来;十秒之后的情况就和实例三不一样了;

linux中信号的API详解实例的更多相关文章

  1. (转)linux 中特殊符号用法详解

    linux 中特殊符号用法详解 原文:https://www.cnblogs.com/lidabo/p/4323979.html # 井号 (comments)#管理员  $普通用户 脚本中 #!/b ...

  2. gvoory脚本中关于HttpClient使用详解实例

    一.gvoory脚本中关于HttpClient使用详解实例 HttpClient:是一个接口 首先需要先创建一个DefaultHttpClient的实例 HttpClient httpClient=n ...

  3. Linux中mpstat命令参数详解

    Linux中mpstat命令参数详解 mpstat 是 Multiprocessor Statistics的缩写,是实时系统监控工具.其报告与CPU的一些统计信息,这些信息存放在 /proc/stat ...

  4. Java 8 中的 Streams API 详解

    为什么需要 Stream Stream 作为 Java 8 的一大亮点,它与 java.io 包里的 InputStream 和 OutputStream 是完全不同的概念.它也不同于 StAX 对 ...

  5. Java 8中的 Streams API 详解

    为什么需要 Stream Stream 作为 Java 8 的一大亮点,它与 java.io 包里的 InputStream 和 OutputStream 是完全不同的概念.它也不同于 StAX 对 ...

  6. (转)Java 8 中的 Streams API 详解

    为什么需要 Stream Stream 作为 Java 8 的一大亮点,它与 java.io 包里的 InputStream 和 OutputStream 是完全不同的概念.它也不同于 StAX 对 ...

  7. linux中mv命令使用详解

    mv命令是move的缩写,可以用来移动文件或者将文件改名(move (rename) files),是Linux系统下常用的命令,经常用来备份文件或者目录. 1.命令格式: mv [选项] 源文件或目 ...

  8. linux中pipe和dup2详解

    1.什么是管道 管道是半双工的,数据只能向一个方向流动:需要双方通信时,需要建立起两个管道: 只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程): 单独构成一种独立的文件系统:管道对于管道两端的进 ...

  9. 【转】linux 中dd命令使用详解

    原文网址:http://xiaozhuang.blog.51cto.com/4396589/850657 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究 ...

随机推荐

  1. HTML5新增常用标签

    1.header 标签定义文档的页眉(介绍信息). <body> <article> <header> <h1>What Does WWF Do?< ...

  2. 原生javascript禁用和屏蔽鼠标右键

    (function(){ var doc=document, ua = navigator.userAgent.toLowerCase(), check = function(r){return r. ...

  3. UOJ226. 【UR #15】奥林匹克环城马拉松 [组合数学,图论]

    UOJ 思路 我们知道关于有向图欧拉回路计数有一个结论:在每个点入度等于出度的时候,答案就是 \[ t_w(G)\prod (deg_i-1)! \] 其中\(t_w(G)\)是以某个点为根的树形图个 ...

  4. mpvue开发坑点总结

    最近一直在开发微信小程序,趁着空闲时间总结下使用情况. 现在项目目前使用的是 mpvue:^1.0.11 版本,后续看看更新情况. 文档在此: http://mpvue.com/mpvue/#_2 # ...

  5. ZR#1004

    ZR#1004 解法: 对于 $ (x^2 + y)^2 \equiv (x^2 - y)^2 + 1 \pmod p $ 化简并整理得 $ 4x^2y \equiv 1 \pmod p $ 即 $ ...

  6. PHP-FPM远程代码执行漏洞(CVE-2019-11043)

    0x00 简介 在长亭科技举办的 Real World CTF 中,国外安全研究员 Andrew Danau 在解决一道 CTF 题目时发现,向目标服务器 URL 发送 %0a 符号时,服务返回异常, ...

  7. 【CSP模拟赛】坏天平(数学&思维)

    蹭兄弟学校的题目做还不用自己出题的感觉是真的爽 题目描述 nodgd有一架快要坏掉的天平,这架天平右边的支架有问题,如果右边的总重量比左边多太多,天平就彻底坏掉了.现在nodgd手上有n种砝码,质量分 ...

  8. arts 打卡12周

    一 算法:  字符串转换整数 (atoi)   请你来实现一个 atoi 函数,使其能将字符串转换成整数. 首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止. 当我们寻找 ...

  9. sql查询性能调试,用SET STATISTICS IO和SET STATISTICS TIME---解释比较详细

            一个查询需要的CPU.IO资源越多,查询运行的速度就越慢,因此,描述查询性能调节任务的另一种方式是,应该以一种使用更少的CPU.IO资源的方式重写查询命令,如果能够以这样一种方式完成查 ...

  10. Guided Hacking DLL Injector 3.3

    Guided Hacking DLL Injector 3.3 https://guidedhacking.com/resources/guided-hacking-dll-injector.4/ I ...