最近看了一下LInux信号的相关内容,一些博客说的不是很清楚,所以我又整理了一下。
主要不清楚的点在于红色标注的地方,可以参考代码运行一下 测试4 看看。
信号的状态
到达:表示执行信号处理
未决:记录信号是否产生
阻塞:表示是否阻塞某个信号,相当于一个开关
信号在内核中的处理,用两个状态字{阻塞/读写,未决/只读}
信号 阻塞mask 未决mask 信号处理函数
1 1 1 //信号产生了,但是由于阻塞还未处理
2 0 0 //信号产生就直接处理
3 1 0 //信号还未产生
... ...
阻塞mask在 task_struct中使用{sigset_t blocked;}来记录,占据64bit
为1表示阻塞,为0表示非阻塞
阻塞mask可以sig...系列函数来设置,通过man sigsetops查看
未决mask:1表示未决(信号已经产生),0表示信号可以抵达(未产生信号)
在接受信号时,内核首先判断信号屏蔽状态字是否阻塞,
如果该信号被设为阻塞,那么信号未决状态字(pending)相应位置1,
表示有信号到达但是由于阻塞没有办法处理,处于未决状态;
如果该信号被设为非阻塞,则直接调用信号处理
在解除信号阻塞时,如果未决状态字为1,那就就处理该信号,并将未决状态置位0
可以利用 int sigpending(sigset_t *set);函数查看有那些信号由于阻塞尚未被处理
#include
#include
#include
//文件 系统调用
#include
#include
// 信号
#include
//获取限制
#include
#include
// wait调用
#include
// 断言
#include
// 结束状态处理
void handle_exit(int wstatus){
if(WIFEXITED(wstatus)){
// 正常结束,结束状态
printf("normal: %d\n",WEXITSTATUS(wstatus));
} else {
if(WIFSIGNALED(wstatus)){
// 信号状态
printf("abnormal: signal %d\n",WTERMSIG(wstatus));
}
}
}
// alarm 处理
void alarm_handle(int num){
printf("alarm_handle: %d\n",num);
alarm(1);
}
void int_handle(int num){
printf("int_handle: %d\n",num);
}
int main ()
{
//测试 1 wait 的使用
/*
int wstatus;
pid_t pid;
pid = fork();
assert(pid!=-1);
if(pid==0){
// son
exit(7);
} else {
wait(&wstatus);
handle_exit(wstatus);
}
pid = fork();
assert(pid!=-1);
if(pid==0){
// son
abort();
} else {
waitpid(pid, &wstatus, 0);
handle_exit(wstatus);
}
*/
//测试 2 信号的注册 发送信号
/*
int wstatus;
int pid = fork();
assert(pid!=-1);
if(pid==0){
// son
execv("./hello.out",NULL);
} else {
// father
sleep(1); // 睡眠一下,等待子进程完成信号的注册
kill(pid, SIGINT); //发送信号
waitpid(pid, &wstatus, 0);
handle_exit(wstatus);
}
*/
//测试 3 alarm循环
/*
signal(SIGALRM,alarm_handle);
alarm(1);
while(1)
pause();
*/
// 测试4 信号状态
/*
sigset_t old;
sigset_t new;
sigset_t pending;
// 注册 SIGINT 的处理函数
signal(SIGINT,int_handle);
// 读取并打印现在的状态字
sigprocmask(0,NULL,&old);
sigpending(&pending);
printf("读取并打印现在的状态字\n");
printf("block: %lu\n", sigismember(&old,SIGINT) );
printf("pendi: %lu\n", sigismember(&pending,SIGINT) );
// 阻塞 SIGINT
printf("\n阻塞 SIGINT\n");
sigemptyset(&new);
sigaddset(&new, SIGINT);
sigprocmask(SIG_BLOCK,&new,&old); //阻塞
sigprocmask(0,NULL,&old); //读取现在的状态
sigpending(&pending);
printf("block: %d\n", sigismember(&old,SIGINT) );
printf("pendi: %d\n", sigismember(&pending,SIGINT) );
// 给自己发送信号, 由于已经阻塞,不能处理
printf("\n给自己发送信号, 由于已经阻塞,不能处理\n");
raise(SIGINT);
sigprocmask(0,NULL,&old);
sigpending(&pending);
printf("block: %d\n", sigismember(&old,SIGINT) );
printf("pendi: %d\n", sigismember(&pending,SIGINT) );
sleep(1); //等待信号处理
// 解除阻塞
printf("\n解除阻塞\n");
sigprocmask(SIG_UNBLOCK,&new,&old);
sigpending(&pending);
printf("block: %d\n", sigismember(&old,SIGINT));
printf("pendi: %d\n", sigismember(&pending,SIGINT) );
sleep(1); //等待信号处理
*/
return 0;
}