unix/linux信号:1. 基础介绍

1. 基本概念

  • 信号是事件发生时对进程的通知机制,可以通知其他进程也可以通知进程自己。信号通常源自于内核。
  • 信号通常分为两类: 一是 内核向进程通知,通常称为标准信号或传统信号(1~31)。 二是另外的一组实时信号。
  • 进程可以通过信号掩码暂时将到来的信号阻塞。
  • 进程对信号的到来有如下几种默认处理方式:
1.忽略信号
2.终止进程
3.产生核心转储文件,同时终止进程
4.停止进程
5.之前暂停后再度恢复进程的执行

除了默认的处理方式,也可以为信号安装自定义处理方式。
注意:无法为信号安装生成coredump的自定义处理程序,但是可以在自定义程序中调用exit或者abort(),abort()将会触发SIGABRT信号,该信号将引发进程产生coredump文件。


2. 常见信号

SIGABRT:终止进程,产生coredump文件
SIGALRM:定时器到期
SIGBUS:某种内存访问失败 coredump
SIGCHLD:子进程终止时,向父进程发送的信号
SIGCONT:将该信号发送给已停止的进程,进程将恢复运行。
SIGFPE:特性类型的算术错误产生,比如除0
SIGHUP:当终端断开时,将发送该信号给终端控制进程。通常用于守护进程 Init、httpd/inetd, 许多守护进程在收到SIGHUB信号的时候会重新初始化并重新读取配置
SIGINFO:用于获取前台进程组的状态信息
SIGINT:用户键入的终端终端字符
SIGIO:利用fcntl系统调用,可用于特定类型的打开文件描述符发送IO事件时产生该信号。
SIGKILL:终止信号
SIGPIPE:当某一进程向管道、FIFO或套接字写入信息时,如果这些设备无响应的阅读进程,那么系统将产生改信号
SIGPWR:电源故障信号,init进程收到该信号后,会快速有序的关闭系统、
SIGQUIT:键入退出字符 ctrl+\  ,通常会终止进程同时产生coredump文件。
SIGSEGV:内存引用无效  coredump
SIGSTOP:停止信号,类似SIGKILL
SIGSYS:系统调用发生错误
SIGTERM:终止进程的标准信号, kill命令发出的信号。 kill -9 发出SIGKILL信号
SIGTRAP:用来实现断点调试功能
SIGTSTP:作业控制停止信号,通常ctrl+z触发
SIGURG:系统发送该信号给一个进程,表示套接字上存在带外(也称紧急)数据
SIGUSR1和SIGUSR2: 开发人员自定义使用,可用于进程间同步。
SIGWINCH:终端窗口尺寸发生变化。
SIGXCPU:进程CPU时间超出对应的资源限制

3. 设置自定义处理程序

3.1 signal

signal()和sigaction(), signal()是原始API,接口比较简单,但是不同unix之间存在差异。sigaction()移植性更好。

#include <signal.h>
void (*signal(int sig, void (*handler)(int)) )(int);  
其中hanlder为信号的处理程序,sig为信号,handler参数int为sig。
signal返回之前的信号处理程序。--- 注意理解这个声明表达方式。

void (*oldHandle)(int);
oldHandler = signal(SIG_INT, newHandler);

对于 void (*signal(int sig, void (*handler)(int)) )(int);的解释, 参数是个函数指针,返回值也是个函数指针。简化理解

typerdef void (*sigHandler_t) (int);
sighandler_t  signal(int sig, sighandler_t handler);

signal在指定函数地址是,可以用SIG_DFL来表示使用默认信号处理程序。 使用SIG_IGN表示忽略信号。signal调用失败则会返回SIG_ERR

3.2 sigaction
#include <signal.h>
int sigaction(int sig, const struct sigaction *act, struct sigaction *oldact);  
// sig取值可以是除去 SIGKILL和SIGSTOP外的任何信号

struct sigaction {
	void (*sa_handler)(int); // signal的处理函数句柄
	sigset_t sa_mask; // 一组信号,在调用handler时阻塞这组信号集
	int sa_flags; // 位掩码,用来控制信号处理过程的各个选项
	void (*sa_restorer)(void);
}

4. 信号操作

4.1 发送信号kill()
#include<signal.h>
int kill(pid_t pid, int sig);
pid 不同取值的含义
1. pid>0 信号发个pid指定的进程
2. pid = 0 信号发给与调用进程同组的每个进程,包括调用进程本身
3. pid < -1 向组ID等于改pid绝对值得进程组内所有下属进程发送信号
4. pid = -1 广播信号,调用进程将信号发送给出init和自身的有权限的进程

向进程发送kill信号前提是当前进程有权限给请求的pid发送信号,如果没有,kill调用失败,errno置位EPERM。
当sig为0时表示空信号,空信号可以检测对应的pid是否存在,如果不存在,kill返回失败,同时errno置为ESRCH。

4.2 raise()和killpg()
#include <signal.h>
int raise(int sig); // 进程对自身发信号,相当于 kill(getpid(), sig);
int killpg(pid_t pgrp, int sig); // 向某一进程组发送一个信号
void psignal(int sig, const char *msg);  // 返回信号对应的字符串解释
4.3 信号集操作函数
#include <signal.h>
int sigemptyset(sigset_t *set);  // 初始化信号集
int sigfillset(sigset_t *set); // 填充信号集
int sigaddset(sigset_t *set, ing sig); // 向信号集里新增信号
int sigdelset(sigset_t *set, int sig); // 从信号集里删除信号
int sigismember(const sigset_t *set, int sig); // 测试当前信号是否在信号集

int sigandset(sigset_t *set, sigset_t *left, sigset_t *right); // 将信号集left和right取交集后存于set
int sigorset(sigset_t *set, sigset_t *left, sigset_t *right); // 将信号集left和right取并集后存于set
int sigemptyset(const sigset_t *set)// 如果信号集为空,返回true
4.4 信号掩码

每个进程都有自己的信号掩码,即一组信号,并将阻塞其针对该进程的信号传递。
线程信号掩码可以用pthread_mask函数来检查和修改。

#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
// how参数解读, 当how为
	SIG_BLOCK时,将set和当前的信号集取并集
	SIG_UNBLOCK时,将set中包含的信号从当前信号集中取出
	SIG_SETMASK时,将set的信号集赋给当前信号信号集
如果想获取当前信号集,set指针设置为null,这时会忽略how参数,在old中返回当前信号集。
  • 到达进程的信号如果被掩码阻塞了,则信号会进入等待信号集中,当阻塞信号解除时,等待信号会传递给进程,但是同一信号被多次阻塞,解阻塞后只会传递一次,阻塞信号也是通过掩码保存。获取等待信号的api如下
#include <signal.h>
int sigpending(sigset_t *set); // set返回为等待信号集
4.5 等待信号: pause()

调用pause()将暂停进程的执行,直到信号处理器函数中断改调用为止。

#include <signal.h>
int pause(void); 

unix/linux信号:2.API使用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值