信号(一)
[TOC]
##1.信号基本概念
信号是事件发生时堆进程的通知机制,也称为软件中断。信号与硬件中断的相似之处在于打断了程序执行的正常流程。
##2.信号产生的原因及分类
1. 产生的诸多信号通常都来源于内核。引发内核为进程产生信号的各类事件:
- 硬件发生异常
- 用户键入能够产生信号中断的特殊字符,如ctrl+c
- 发生了软件事件,如该进程的某个子进程退出
2. 信号分为两大类
- 标准信号:内核向进程通知事件,编号范围:1~31
- 实时信号(注:与标准信号的差异后来补。。。)
可以输入 \`kill -l` 命令查看linux内核支持的信号

输入 `man 7 signal` 命令查看信号的默认动作、信号的含义
##3.信号在Linux中的传递过程

我们从左至右的看上面这张图片。
task_struct代表的是进程控制块(PCB)的结构;每个进程在内核中都有一个进程控制 块来维护进程的相关信息。
在task_struct中存储着信号屏蔽状态字(block),信号未决状态字(pending)和handler信息。
综述:向进程发送某个信号,内核首先判断其对应的PCB中 `block`的标志,
- 0代表不阻塞
- 1代表阻塞
若为阻塞状态,则将其对应的未决状态也置为1;若不为阻塞,相应的未决状态赋为0,代表信号可以抵达了。
信号抵达后,也有着不同的处理方式,如 `SIG_DFL` :执行默认的方式; `SIG_IGN` :忽略;或者执行信号处理器程序(即程序员自己编写的程序)。
###①如何获取或操作某进程block信息
| int sigprocmask(int how, const sigset_t *set, sigset_t *oset); |
| -------- | :-----: |
| 功能 | 读取或更改进程的信号屏蔽字(pending)
| 返回值: | 若成功则为0,若出错则为-1 |
| 参数 | ||
|---|---|---|
| how | SIG_BLOCK | 参数set包含了希望添加到block中屏蔽字 |
| SIG_UNBLOCK | 参数set包含了希望解除的屏蔽字 | |
| SIG_SETMASK | 参数set设置为当前信号屏蔽字 | |
| set | ||
| oset | 原来的信号屏蔽字 |
###②如何获取某进程pending信息
| int sigpending(sigset_t *set) | |
| -------- | :-----: |
| 功能 | 获取信号未决状态字(pending)信息 |
| 返回值 | 若成功则为0,若出错则为-1 |
###③补充知识(信号集操作函数)
| 函数 | 作用 |
| -------- | :-----: |
| int sigemptyset(sigset_t *set) | 把信号集清零 |
| int sigfillset(sigset_t *set) | 把信号集制成1 |
| int sigaddset(sigset_t *set, int signo) | 根据signo,把信号集中的对应为置成1 |
| int sigdelset(sigset_t *set, int signo) | 根据signo,把信号集中的对应为置成0 |
| int sigismember(const sigset_t *set, int signo) | 判断signo是否在信号集中 |
###④小demo
SIGINT信号设置阻塞,查看未决关键字
SIGINT信号解除阻塞,查看未决关键字
void handler(int sig)
{
if (sig == SIGINT)
{
printf("recv a sig=%d\n", sig);
printf("\n\n\n");
//fflush(stdout);
}
else if (sig == SIGQUIT)
{
sigset_t uset;
sigemptyset(&uset);
sigaddset(&uset, SIGINT);
//ctr + \ 用来接触 SIGINT 信号
//解除阻塞
sigprocmask(SIG_UNBLOCK, &uset, NULL);
//signal(SIGINT, SIG_DFL) ;
}
}
void printsigset(sigset_t *set)
{
int i;
for (i=1; i<NSIG; ++i)
{
//printf("%d\n",NSIG);
if (sigismember(set, i))
putchar('1');
else
putchar('0');
}
printf("\n");
}
int main(int argc, char *argv[])
{
sigset_t pset; //用来打印的信号集
sigset_t bset; //用来设置阻塞的信号集
sigset_t bbset;
sigset_t tmpset;
sigemptyset(&bset);
sigaddset(&bset, SIGINT);
if (signal(SIGINT, handler) == SIG_ERR)
ERR_EXIT("signal error");
if (signal(SIGQUIT, handler ) == SIG_ERR)
ERR_EXIT("signal error");
//读取或更改进程的信号屏蔽字 这里用来阻塞ctrl+c信号
//ctrl+c信号被设置成阻塞,即使用户按下ctl+c键盘,也不会抵达
sigprocmask(SIG_BLOCK, &bset, NULL);
for (;;)
{
//获取未决字信息
sigpending(&pset);
printf("block......\n\n\n");
sigemptyset(&tmpset);
sigprocmask(SIG_BLOCK,&tmpset,&bbset);
printsigset(&bbset);
//打印信号未决字
printf("pending......\n");
printsigset(&pset);
sleep(1);
}
return 0;
}

浙公网安备 33010602011771号