linux下的信号机制(signal)

1。linux的信号机制
信号时内核提供的一种异步消息机制,用于内核对进程发送异步通知事件,可以理解为进程执行的流程中的一个软中断。
信号可以直接进行用户空间进程和内核进程之间的交互,内核进程也可以通过它来通知用户空间进程发送了哪些事件。
一个完整的信号使用由:
(1)内核信号产生
(2)用户进程信号注册
(3)信号在用户进程进程中注销
(4)执行信号处理函数
常见的信号:
(1)在进程在一个没有打开的管道上等待时,内核发出SIGPIPE信号
(2)进程在shell中前台执行时,用户按下CTRL+C组合,向进程发送SIGINT信号
(3)用户使用kill命令来向进程发送信号
(4)进程访问非法的内存地址,内核向进程发送信号SIGSEGV段错误
(5)一个进程使用系统调用来向另外一个进程发送信号
(6)发送各种运行异常时,内核向进程发送SIGFPE信号。
2.信号的处理机制
用户进程对信号的三种处理方式:
(1)忽略信号,即不对信号做任何操作。但是SIGKILL和SIGSTOP信号不能被忽略。
(2)捕捉信号,定义信号处理函数,以便捕捉到这个信号时执行相应的处理函数。
(3)执行默认的操作。
常见的信号的默认操作有:
SIGHUP:终止,该信号在用户终端结束时发出
SIGINT:终止,通常是用户键入CTRL+C发出的
SIGQUIT:终止,与SIGINT类似,但由CTRL+\发出
SIGILL:当一个进程企图执行一个非法指令时,发出的信号,使得进程终止
SIFFPE:该信号发生在致命的算术运算错误,使得进程终止
SIGKILL:该信号是不能被忽略的信号,使得进程立即终止
SIFALRM:定时器信号
SIGSTOP:该信号不能被忽略,使得进程暂停
SIGCHLD:子进程状态改变,父进程会受到这个信号,一般默认操作时忽略
SIGABORT:进程异常终止时发出该信号
内核对进程管理的PCB中,包含信号标志位,若信号发生,则相应位就会被置1.在进程从内核态返回到用户态时,首先会进行检查信号相关信息,如果检测到相应信号的比特位被置1了,则在用户态中先执行信号处理函数,再返回用户进程。信号处理函数是在用户进程之外进行的操作。
3.发送信号
向一个进程中发送信号可以使用函数kill,raise,alarm,pause
默认情况下,kill命令发送SIGTERM以终止一个进程。
(1)kill函数:
#include <signal.h>
#include <sys/types.h>
int kill(pid_t pid,int siq);
(1)pid > 0,表示要发送进程的进程号
(2)pid=0,表示把信号发送到与当前进程同组的所有进程
(3)pid = -1,表示发送到当前的进程表中的所有进程。
(4)pid < -1,表示处于进程组-pid中的所有进程进程。
函数成功返回0,失败返回-1.
(2)raise函数只允许进程向自身发送信号。
#include <signal.h>
int raise(int sig);
(3)alarm函数
使用alarm函数可以在指定一段时间后给自己本身发送SIGALRM信号,可以作为定时器使用
#include <unistd.h>
unsigned int alarm(unsigned int seconds); 利用该函数可以实现定时的功能。指定了时间,一到时间就会向进程发送SIGALRM信号,成功返回0,出错返回-1.
(4)pause函数
#include <unistd.h>
int pause(void);
使进程等待信号。出错返回-1.
4.信号处理函数
signal函数:
#include <signal.h>
typedef void(*sighander_t)(int);
sighandler_t signal(int signum,singdler_t handler);
signal函数将handler参数指向的函数注册成为参数signum所代表的处理函数。signal函数的返回值就是这个信号原来的处理函数,若返回SIG_ERR。则说明有错误发生。注册成功后,所注册的函数就会被信号处理时进行调用,代替了默认的行为,称为信号被捕捉。
使用signal函数时,应该注意:
(1)handler参数的值可以是SIG_IGN或SIG_DFL,SIG_IGN表示忽略这个信号,SIG_DFL表示对信号的处理重设为默认的行为,也可以是自己定义的函数指针。
(2)有些信号是不可以被忽略或者捕捉的,比如SIGKILL和SIGSTOP
sigaction函数
#
#include <signal.h>
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
其中,signum是信号代码。 act指向sigaction结构的一个指针,用来指定对特定信号的处理。oldact保存原来对信号的处理操作。
成功返回0,错误返回-1.
5.信号集的操作:
信号集用sigset_t类型表示,在linux系统上有一组函数专用于对信号集进行操作:
#include <signal.h>
int sigemptyset(sigset_t *set);//清空信号集
int sigfillset(sigset_t *set);//将所有的信号加入信号集
int sigaddset(sigset_t *set, int signum);//将指定的信号加入信号集中
int sigdelset(sigset_t *set, int signum); //将指定的信号从信号集中去除
int sigismember(const sigset_t *set, int signum);//判断一个指定的信号是否在信号集中,返回1表示在,0表示不再,-1表示出错。
信号集中的信号并不是真正可以处理的信号,只有当信号处于非阻塞状态才可以使用。
set指向要操作的信号集,signum代表一个指定的信号
在调用sigaction函数时,可以设置信号处理时要屏蔽的信号。
实际上,在代码中也可以直接设置或获取进程的信号掩码,如下:
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
参数说明:
how指定操作信号掩码的方式,函数将根据how指定的方式,
设置当前进程的信号掩码。
how的取值范围:
SIG_BLOCK:将set参数指向的信号集中的信号加入到信号
掩码中。
SIG_UNBLOCK:将set参数指向的信号集中的信号从信号掩
码中删除。
SIG_SETMASK:将set参数指向的信号集设置为信号掩码
oset是指信号屏蔽字,函数成功返回0,出错返回-1.
6.信号的屏蔽方式:
方式一
sigset_t sigset;
sigemptyset(&sigset);
sigaddset(&sigset, SIGUSR1);
sigprocmask( SIG_BLOCK, &sigset, NULL);
方式二
sigset_t sigset;
// 得到当前的信号掩码
sigprocmask( SIG_SETMASK, NULL, &sigset);
sigaddset(&sigset, SIGUSR1); // 将要屏蔽的信号加入
sigprocmask( SIG_SETMASK, &sigset, NULL);
7.解除信号屏蔽的方式
方式一
sigset_t sigset;
sigemptyset(&sigset);
sigaddset(&sigset, SIGUSR1);
sigprocmask (SIG_UNBLOCK, &sigset, NULL);
方式二
sigset_t sigset;
// 得到当前的信号掩码
sigprocmask( SIG_SETMASK, NULL, &sigset);
sigdelset(&sigset, SIGUSR1); // 将要屏蔽的信号加入
sigprocmask (SIG_SETMASK, &sigset, NULL)
8.总结:在处理信号时,一般的操作过程是
(1)定义信号集
(2)设置信号屏蔽为,使用sigprocmask函数
(3)定义信号处理函数
(4)测试信号sigpending函数(原型:int sigpending(sigset_t *set),成功返回0,出错返回-1)
信号这边内容比较多,实例参见linux代码。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ShaYQ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值