Unix高级编程:信号处理函数的注册、信号的产生、阻塞、未决
来源:互联网 发布:淘宝贷款怎么申请 编辑:程序博客网 时间:2024/05/11 18:36
一、使用signal(2)向进程注册信号处理函数
"kill -l" 显示所有可用的系统信号的编号
/*举例向进程注册2号信号的用户自定义的处理程序,signal.c*/
#include <stdio.h>
#include <signal.h>
void handle(int signum) {
printf("recv signal num %d..\n", signum);
return;
}
int main(void) {
#if 0 /* 想放开的时候,把 0 变成 1 */
handle是signal回调函数的参数,在signal函数的实现中调用了handle函数,handle函数参数是信号的编号
#endif
signal(SIGINT, &handle);
while(1);
return 0;
}
补充:
1)注释补充
// C++的注释
/**/ C语言的注释,不能嵌套
#if 0
#endif 条件编译注释,0 换成 1 则让注释内容再次生效
2)信号场景的理解
1. 用户输入命令,在shell下启动一个前台进程
2. 用户按下Ctrl+C,这个键盘的输入产生一个硬件中断
3. 如果CPU当前正在执行这个进程的代码,则该进程的用户空间代码暂停执行,CPU"从用户态切换到内核态处理硬件中断"
4. 终端驱动程序将Ctrl+C解释成一个 SIGINT 信号,记录在该进程的PCB中
5. 当某个时刻,进程需要从内核态返回到用户态的时候,首先处理PCB中记录的信号,发现有一个SIGINT信号待处理,而这个信号的默认处理动作是终止该进程
6. 现场的情况:
————信号的处理函数是用户自定义的,调用用户自定义的信号处理函数,调用完毕,继续返回到内核态,该信号的记录清空,执行第 5 步。
二、信号的产生、闹钟与睡眠
第一种:"硬件产生",Ctrl+C 或者 Ctrl+\
第二种:"使用命令产生" kill -信号编号 pid
第三种:"使用函数产生" kill/raise/alarm等
"kill"(2)
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
功能:给一个进程发送信号(给进程号为pid的进程发送sig信号)
参数:
"pid" 进程pid号(>0 的情况)
"sig" 信号的编号
返回值:
成功 - 返回 0
失败 - 返回-1,errno被设置
/*举例验证,使用kill给某个进程发送信号,kill.c*/
#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
pid_t pid;
int signo;
pid = atoi(argv[1]); //从命令行获取pid和signo
signo = atoi(argv[2]);
kill(pid, signo); //给指定的进程发送signo信号
return 0;
}
"raise"(3)
#include <signal.h>
int raise(int sig);
功能:发送一个信号给自己的进程
参数:"sig" 指定要发送给自己的信号编号
返回值:
成功 - 返回 0
失败 - 返回非 0
/*举例验证,给自己发送2号信号,signal3.c*/
#include <stdio.h>
#include <signal.h>
void handle(int signum) {
printf("signal num %d..\n", signum);
return;
}
int main(void) {
int i = 0;
signal(SIGINT, &handle);
while(i++ < 5) {
printf("i = %d\n", i);
if(i == 3) {
raise(2); //i=1 i=2 i=3 signal num 2.. i=4 i=5
}
}
return 0;
}
"alarm"(2) "闹钟"
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
功能:整理一个信号在seconds指定的时间到达自己的进程
参数:"seconds" 指定的时间,默认单位:秒
0 没有设置新闹钟
返回值:
成功 - 返回剩余的秒数,在闹钟时间到达的时候产生 14)SIGALRM 信号,发送给自己的进程
失败 - 返回 0 取消闹钟
/*举例验证alarm函数的使用,代码参见 alarm.c*/
#include <stdio.h>
#include <unistd.h>
int main(void) {
int i = 0;
alarm(1); //设置闹钟为1秒
for(;; i++) {
printf("i = %d\n", i);//可用来测试CPU的速度
}
return 0;
}
"sleep"(3) "睡眠"
#include <unistd.h>
unsigned int sleep(unsigned int seconds);
功能:给程序指定seconds时间的睡眠
参数:"seconds" 指定的时间,默认单位:秒
返回值:
成功 - 返回 0
失败 - 返回剩余的秒数,在进程被信号中断的时候,返回剩余秒数
三、信号阻塞和未决信号
信号阻塞:所谓的信号阻塞是进程对某一个或一些信号进行阻塞。
进程调用"sigprocmask"函数设置对信号的阻塞
"sigprocmask"(2)
#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
功能:检测或改变为阻塞的信号
参数:
类型sigset_t /* 集合类型,用于标识信号的阻塞和未决状态 */
"how"
SIG_BLOCK 将进程当前的信号组合集合和set指定的集合/*合并*/
SIG_UNBLOCK 将set集合里指定的信号从进程当前阻塞的信号集里/*移除*/解除set信号集里指定的信号的阻塞
SIG_SETMASK 将进程阻塞的信号集/*设置为参数set的集合*/
"set" 要操作的/*新的信号集*/
"oldset" 如果oldset非空,将进程的原先的阻塞信号集/*存储*/到oldset指定的集合里;如果oldset是 NULL,则不会存储原来的信号阻塞集
返回值:
成功 - 返回 0
失败 - 返回 -1
/*举例验证,阻塞进程中的2号信号,sig2.c*/
#include <stdio.h>
#include <signal.h>
void handle(int signum) {
printf(" recv signum: %d\n", signum);
return ;
}
int main(void) {
sigset_t set;
//初始化信号集set
sigemptyset(&set);
//向set信号集里添加2号信号
sigaddset(&set, SIGINT);
//注册2号信号的处理函数为handle
signal(2, handle);
//将信号集合set设置为当前进程的阻塞集合
sigprocmask(SIG_SETMASK, &set, NULL);
while(1);
return 0;
}
"未决信号"
信号产生了,但是信号还没有被递达,这时候信号的状态称为未决状态,这个信号称为未决信号。
对"sigset_t类型的操作函数(3)"使用下列:
"sigemptyset" //初始化,清空信号集
#include <signal.h>
int sigemptyset(sigset_t *set);
功能:将集合里的成员全部清空
参数:"set" 指定的信号集合
返回值:
成功 - 返回 0
失败 - 返回 -1
"sigfillset" //填充信号集
#include <signal.h>
int sigfillset(sigset_t *set);
功能:将集合的所有成员全部填充
参数:"set" 指定的信号集合
返回值:
成功 - 返回 0
失败 - 返回 -1
"sigaddset" //添加信号到信号集
#include <signal.h>
int sigaddset(sigset_t *set, int signum);
功能:将signum信号添加到set指定的集合里
参数:
"set" 指定的信号集合
"signum" 指定的信号编号
返回值:
成功 - 返回 0
失败 - 返回 -1
"sigdelset" //删除信号集里指定的信号
#include <signal.h>
int sigdelset(sigset_t *set, int signum);
功能:从set指定的集合里将signum指定的信号编号删除
参数:
"set" 指定的信号集合
"signum" 指定的信号编号
返回值:
成功 - 返回 0
失败 - 返回 -1
"sigismember" //测试信号是否是信号集里的成员
#include <signal.h>
int sigismember(const sigset_t *set, int signum);
功能:测试signum是否是set集合里的一个成员
参数:
"set" 指定的信号集合
"signum" 指定的信号编号
返回值:
成功 - 返回 1 代表signum是set集合的成员,0 代表不是。
失败 - 返回 -1
"检测信号是否处于未决状态",需要使用sigpending函数:
"sigpending"(2)
#include <signal.h>
int sigpending(sigset_t *set);
功能:检测未决信号
参数:"set" 未决信号集被返回到set指定的集合里
返回值:
成功 - 返回 0
失败 - 返回 -1
/*举例验证未决信号,对2号信号阻塞时进行检测 sigpending.c*/
#include <stdio.h>
#include <signal.h>
void handle(int signum) {
printf(" recv signum: %d\n", signum);
return ;
}
int main(void) {
sigset_t set, pset;//pset用于检测
//向进程注册2号信号的处理函数为handle
signal(2, handle);
//初始化set集合为空
sigemptyset(&set);
//将2号信号添加到集合set里
sigaddset(&set, 2);
//设置进程对信号的阻塞的集合
sigprocmask(SIG_BLOCK, &set, NULL);
while(1) {
//检测进程的未决信号,将未决信号添加到pset的集合里
sigpending(&pset);
//检测2号信号是否处于未决状态
int r = sigismember(&pset, 2);
if(r > 0) {
printf("检测到2号信号为未决信号!\n");
break;
}
}
return 0;
}
"可靠信号":
当在进程中设置了对某个信号阻塞,当有同一个信号多次到达的时候,解除信号阻塞的时候,"会有1个信号的多次捕获"。
此为可靠信号(34-64 号)。
"不可靠信号":
当在进程中设置了对某个信号阻塞,当有同一个信号多次到达的时候,解除信号阻塞的时候,"对这个信号只有1次捕获,造成了信号的丢失"。
此为不可靠信号(1-31 号)。
/*举例验证,可靠信号与不可靠信号,kekao.c*/
#include <stdio.h>
#include <signal.h>
void handle(int signum) {
printf("recv signum: %d\n", signum);
return ;
}
int main(void) {
sigset_t set, oset;
signal(35, handle);//1-31信号,发送多次,捕获1次
sigemptyset(&set);
sigaddset(&set, 35);
sigemptyset(&oset);
sigprocmask(SIG_SETMASK, &set, &oset);
sleep(20);
sigprocmask(SIG_SETMASK, &oset, NULL);//恢复原来的信号
return 0;
}
"kill -l" 显示所有可用的系统信号的编号
/*举例向进程注册2号信号的用户自定义的处理程序,signal.c*/
#include <stdio.h>
#include <signal.h>
void handle(int signum) {
printf("recv signal num %d..\n", signum);
return;
}
int main(void) {
#if 0 /* 想放开的时候,把 0 变成 1 */
handle是signal回调函数的参数,在signal函数的实现中调用了handle函数,handle函数参数是信号的编号
#endif
signal(SIGINT, &handle);
while(1);
return 0;
}
补充:
1)注释补充
// C++的注释
/**/ C语言的注释,不能嵌套
#if 0
#endif 条件编译注释,0 换成 1 则让注释内容再次生效
2)信号场景的理解
1. 用户输入命令,在shell下启动一个前台进程
2. 用户按下Ctrl+C,这个键盘的输入产生一个硬件中断
3. 如果CPU当前正在执行这个进程的代码,则该进程的用户空间代码暂停执行,CPU"从用户态切换到内核态处理硬件中断"
4. 终端驱动程序将Ctrl+C解释成一个 SIGINT 信号,记录在该进程的PCB中
5. 当某个时刻,进程需要从内核态返回到用户态的时候,首先处理PCB中记录的信号,发现有一个SIGINT信号待处理,而这个信号的默认处理动作是终止该进程
6. 现场的情况:
————信号的处理函数是用户自定义的,调用用户自定义的信号处理函数,调用完毕,继续返回到内核态,该信号的记录清空,执行第 5 步。
二、信号的产生、闹钟与睡眠
第一种:"硬件产生",Ctrl+C 或者 Ctrl+\
第二种:"使用命令产生" kill -信号编号 pid
第三种:"使用函数产生" kill/raise/alarm等
"kill"(2)
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
功能:给一个进程发送信号(给进程号为pid的进程发送sig信号)
参数:
"pid" 进程pid号(>0 的情况)
"sig" 信号的编号
返回值:
成功 - 返回 0
失败 - 返回-1,errno被设置
/*举例验证,使用kill给某个进程发送信号,kill.c*/
#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
pid_t pid;
int signo;
pid = atoi(argv[1]); //从命令行获取pid和signo
signo = atoi(argv[2]);
kill(pid, signo); //给指定的进程发送signo信号
return 0;
}
"raise"(3)
#include <signal.h>
int raise(int sig);
功能:发送一个信号给自己的进程
参数:"sig" 指定要发送给自己的信号编号
返回值:
成功 - 返回 0
失败 - 返回非 0
/*举例验证,给自己发送2号信号,signal3.c*/
#include <stdio.h>
#include <signal.h>
void handle(int signum) {
printf("signal num %d..\n", signum);
return;
}
int main(void) {
int i = 0;
signal(SIGINT, &handle);
while(i++ < 5) {
printf("i = %d\n", i);
if(i == 3) {
raise(2); //i=1 i=2 i=3 signal num 2.. i=4 i=5
}
}
return 0;
}
"alarm"(2) "闹钟"
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
功能:整理一个信号在seconds指定的时间到达自己的进程
参数:"seconds" 指定的时间,默认单位:秒
0 没有设置新闹钟
返回值:
成功 - 返回剩余的秒数,在闹钟时间到达的时候产生 14)SIGALRM 信号,发送给自己的进程
失败 - 返回 0 取消闹钟
/*举例验证alarm函数的使用,代码参见 alarm.c*/
#include <stdio.h>
#include <unistd.h>
int main(void) {
int i = 0;
alarm(1); //设置闹钟为1秒
for(;; i++) {
printf("i = %d\n", i);//可用来测试CPU的速度
}
return 0;
}
"sleep"(3) "睡眠"
#include <unistd.h>
unsigned int sleep(unsigned int seconds);
功能:给程序指定seconds时间的睡眠
参数:"seconds" 指定的时间,默认单位:秒
返回值:
成功 - 返回 0
失败 - 返回剩余的秒数,在进程被信号中断的时候,返回剩余秒数
三、信号阻塞和未决信号
信号阻塞:所谓的信号阻塞是进程对某一个或一些信号进行阻塞。
进程调用"sigprocmask"函数设置对信号的阻塞
"sigprocmask"(2)
#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
功能:检测或改变为阻塞的信号
参数:
类型sigset_t /* 集合类型,用于标识信号的阻塞和未决状态 */
"how"
SIG_BLOCK 将进程当前的信号组合集合和set指定的集合/*合并*/
SIG_UNBLOCK 将set集合里指定的信号从进程当前阻塞的信号集里/*移除*/解除set信号集里指定的信号的阻塞
SIG_SETMASK 将进程阻塞的信号集/*设置为参数set的集合*/
"set" 要操作的/*新的信号集*/
"oldset" 如果oldset非空,将进程的原先的阻塞信号集/*存储*/到oldset指定的集合里;如果oldset是 NULL,则不会存储原来的信号阻塞集
返回值:
成功 - 返回 0
失败 - 返回 -1
/*举例验证,阻塞进程中的2号信号,sig2.c*/
#include <stdio.h>
#include <signal.h>
void handle(int signum) {
printf(" recv signum: %d\n", signum);
return ;
}
int main(void) {
sigset_t set;
//初始化信号集set
sigemptyset(&set);
//向set信号集里添加2号信号
sigaddset(&set, SIGINT);
//注册2号信号的处理函数为handle
signal(2, handle);
//将信号集合set设置为当前进程的阻塞集合
sigprocmask(SIG_SETMASK, &set, NULL);
while(1);
return 0;
}
"未决信号"
信号产生了,但是信号还没有被递达,这时候信号的状态称为未决状态,这个信号称为未决信号。
对"sigset_t类型的操作函数(3)"使用下列:
"sigemptyset" //初始化,清空信号集
#include <signal.h>
int sigemptyset(sigset_t *set);
功能:将集合里的成员全部清空
参数:"set" 指定的信号集合
返回值:
成功 - 返回 0
失败 - 返回 -1
"sigfillset" //填充信号集
#include <signal.h>
int sigfillset(sigset_t *set);
功能:将集合的所有成员全部填充
参数:"set" 指定的信号集合
返回值:
成功 - 返回 0
失败 - 返回 -1
"sigaddset" //添加信号到信号集
#include <signal.h>
int sigaddset(sigset_t *set, int signum);
功能:将signum信号添加到set指定的集合里
参数:
"set" 指定的信号集合
"signum" 指定的信号编号
返回值:
成功 - 返回 0
失败 - 返回 -1
"sigdelset" //删除信号集里指定的信号
#include <signal.h>
int sigdelset(sigset_t *set, int signum);
功能:从set指定的集合里将signum指定的信号编号删除
参数:
"set" 指定的信号集合
"signum" 指定的信号编号
返回值:
成功 - 返回 0
失败 - 返回 -1
"sigismember" //测试信号是否是信号集里的成员
#include <signal.h>
int sigismember(const sigset_t *set, int signum);
功能:测试signum是否是set集合里的一个成员
参数:
"set" 指定的信号集合
"signum" 指定的信号编号
返回值:
成功 - 返回 1 代表signum是set集合的成员,0 代表不是。
失败 - 返回 -1
"检测信号是否处于未决状态",需要使用sigpending函数:
"sigpending"(2)
#include <signal.h>
int sigpending(sigset_t *set);
功能:检测未决信号
参数:"set" 未决信号集被返回到set指定的集合里
返回值:
成功 - 返回 0
失败 - 返回 -1
/*举例验证未决信号,对2号信号阻塞时进行检测 sigpending.c*/
#include <stdio.h>
#include <signal.h>
void handle(int signum) {
printf(" recv signum: %d\n", signum);
return ;
}
int main(void) {
sigset_t set, pset;//pset用于检测
//向进程注册2号信号的处理函数为handle
signal(2, handle);
//初始化set集合为空
sigemptyset(&set);
//将2号信号添加到集合set里
sigaddset(&set, 2);
//设置进程对信号的阻塞的集合
sigprocmask(SIG_BLOCK, &set, NULL);
while(1) {
//检测进程的未决信号,将未决信号添加到pset的集合里
sigpending(&pset);
//检测2号信号是否处于未决状态
int r = sigismember(&pset, 2);
if(r > 0) {
printf("检测到2号信号为未决信号!\n");
break;
}
}
return 0;
}
"可靠信号":
当在进程中设置了对某个信号阻塞,当有同一个信号多次到达的时候,解除信号阻塞的时候,"会有1个信号的多次捕获"。
此为可靠信号(34-64 号)。
"不可靠信号":
当在进程中设置了对某个信号阻塞,当有同一个信号多次到达的时候,解除信号阻塞的时候,"对这个信号只有1次捕获,造成了信号的丢失"。
此为不可靠信号(1-31 号)。
/*举例验证,可靠信号与不可靠信号,kekao.c*/
#include <stdio.h>
#include <signal.h>
void handle(int signum) {
printf("recv signum: %d\n", signum);
return ;
}
int main(void) {
sigset_t set, oset;
signal(35, handle);//1-31信号,发送多次,捕获1次
sigemptyset(&set);
sigaddset(&set, 35);
sigemptyset(&oset);
sigprocmask(SIG_SETMASK, &set, &oset);
sleep(20);
sigprocmask(SIG_SETMASK, &oset, NULL);//恢复原来的信号
return 0;
}
0 0
- Unix高级编程:信号处理函数的注册、信号的产生、阻塞、未决
- 信号的未决 阻塞
- 信号的未决 阻塞 .
- 信号的阻塞与未决
- 十七、Linux系统编程-信号(四)信号在内核中表示、信号的阻塞和未决
- linux信号的阻塞和未决
- linux信号的阻塞和未决
- linux系统编程之信号(三):信号的阻塞与未决
- linux系统编程之信号(三):信号的阻塞与未决
- linux系统编程之信号(三):信号的阻塞与未决
- linux系统编程之信号(五):信号集操作函数,信号阻塞与未决
- linux系统编程之信号(五):信号集操作函数,信号阻塞与未决
- UNIX环境高级编程学习之第十章信号-信号集的操作,让进程阻塞SIGQUIT信号
- 【C语言】【unix c】信号阻塞和未决信号
- 未决信号与信号阻塞
- 未决信号与信号阻塞
- 信号未决与信号阻塞
- 信号“未决”与“阻塞”
- VI的基本编辑命令-快捷命令(6)
- Unix高级编程:环境变量(续)、管道、文件重定向、信号基础
- bottom-bar使用
- 互联网找工作加分项
- 杭电1173 采矿java解题
- Unix高级编程:信号处理函数的注册、信号的产生、阻塞、未决
- 二叉搜索树(BST)插入与查找
- 【Android开发】Fragment的基本使用
- 趋肤效应_集肤效应
- Unix高级编程:pause函数mysleep的实现、可重入函数、定时器、进程间通讯
- jdk动态代理和cglib代理demo及总结
- redis进阶3-排序
- vlc播放网络流延时参数设置
- 初等排序之插入排序