信号是软中断,包涵了4中异常控制(操作系统中程序的异常执行:中断、陷阱、故障、终止)。
- ** sigprocmask、sigsuspend**可以用来做子父进程唤醒
- **sigaction、sigqueue **可以用来做子父进程的信息传递
方法提要
方法 | 说明 | 成功 | 失败 |
---|---|---|---|
注册感兴趣信号 | |||
signal | 注册感兴趣的信号到内核 | 之前设置的信号处理 | SIG_ERR |
sigaction | 注册感兴趣的信号到内核 | 0 | 1 |
kill | 发送给其它进程关闭信号 | 0 | -1 |
raise | 发送给自己关闭信号 | 0 | -1 |
alarm | 定时器 | 0或以前设置的闹钟时间的余留秒数 | |
pause | 挂起线程直到捕捉到一个信号 | ||
信号集合 | |||
sigemptyset | 清空、初始化一个信号集 | 0 | -1 |
sigfillset | 初始化一个信号集 | 0 | -1 |
sigaddset | 添加一个信号 | 0 | -1 |
sigdelset | 删除一个信号 | 0 | -1 |
sigismember | 判断集合中是否有这个信号 | 1 | 0 |
屏蔽信号操作 | |||
sigprocmask | 屏蔽一个信号集 | 1 | 0 |
sigpending | 返回在信号被阻塞时,传递到进程的阻塞信号 | 1 | 0 |
sigsuspend | 原子操作:挂起进程,直到接收到信号集中的信号,执行信号处理函数,sigsuspend返回 | -1,errno=EINTR | |
abort | 使进程异常终止 | ||
sleep | 进程休眠 | 0或未休眠完的秒数 | |
sigqueue | 发送信号及信息,通过sigaction接受 | 0 | -1 |
跳转 | 原子操作,不会被新的信号中断 | ||
sigsetjmp | 跳转点 | 直接调用,返回0;siglongjmp调用,返回非0 | |
siglongjmp | 跳转 |
名称解释
- 信号概念:每个信号都有一个名字,以SIG。
特点
-
信号来的时候。os会停止进程执行,执行信号处理程序。信号处理程序执行完成,继续执行进程停止地方继续执行。
-
信号来源:
- 用户按终端键时,引发终端产生的信号。例如:Ctrl+C<陷阱>
- 硬件异常产生信号:除数为0、无效的内存引用。例如:内存缺页。<故障>
- 进程调用kill(2)函数可将任意信号发送给另一个进程或进程组。<终止>
- 用户可以kill(1)命令将信号发送给其它进程。<终止>
- 当检测到某种软条件已经发生,并应将其通知有关进程也产生信号。例如:<陷阱>
-
信号处理:
- 忽略信号:大多数信号可使用这种方式处理,除了SIGKILL 和 SIGSTOP.
- 捕捉信号: 进程在接受到某种信号的时候,内核调用一个用户函数处理。
- 执行系统默认动作:大多数信号的系统默认动作是终止该进程。终止+core
-
信号集:能表示多个信号集合 (signal set) 的数据类型。
-
信号列表:
名称 | 产生 | 说明 | 默认动作 | 建议处理方式 |
---|---|---|---|---|
SIGABRT | abort函数 | 异常终止(abort) | 终止+core | |
SIGALRM | alrm函数设置的定时器超时 | 定时器异常(alarm) | 终止 | |
SIGBUS | 出现某些类型的内存故障,当进程通过mmap访问内存I/O,并超出了范围 | 硬件故障 | 终止+core | |
SIGCANCEL | solaris线程 | 线程库内部使用 | 忽略 | |
SIGCHLD | 当一个进程终止或停止时,SIGCHLD信号被送给其父进程。 | 子进程状态改变 | 忽略 | 父进程在信号处理函数中调用wait函数可以取得子进程的ID和其终止状态 |
SIGCONT | 此作业控制信号发给需要继续运行,但当前处于停止状态的进程 | 是暂停进程继续 | 继续/忽略 | |
SIGEMT | 硬件故障 | 终止+core | ||
SIGFPE | 除以0、浮点数溢出 | 算术异常 | 终止+core | |
SIGFREEZE | 此信号仅solaris定义 | 检查单冻结 | 忽略 | |
SIGHUP | 终端接口检查到一个连接断开,则将次信号送给与该终端相关的控制进程(会话首进程) | 连接端口 | 终止 | |
SIGILL | 非法硬件指令 | 终止+core | ||
SIGINFO | BSD的信号,当用户按状态键(Ctrl+T)时,终端驱动程序产生此信号并发送至前台进程组中的每一个信号。 | 请求 | 忽略 | |
SIGINT | Ctrl+C | 终端中断符 | 终止 | |
SIGIO | linux中,SIGIO与SIGPOLL具有相同值 | 异步I/O | 终止/忽略 | |
SIGIOT | 硬件故障 | 终止+core | ||
SIGJVM1 | Solaris上为java虚拟机预留的一个信号 | java虚拟机内部使用 | 忽略 | |
SIGJVM2 | Solaris上为java虚拟机预留的一个信 | java虚拟机内部使用 | 忽略 | |
SIGKILL | 不能被捕捉 | 终止 | 终止 | |
SIGLOST | 运行在Solaris NFSv4 客户端系统中的进程,恢复阶段不能重新获得锁,此时将由这个信号通知进程 | 资源丢失 | 终止 | |
SIGLWP | Solaris的线程库内部使用 | 线程库内部使用 | 终止/忽略 | |
SIGPIPE | 管道的读进程终止时写写管道,则产生次信号 | 写至无读进程的管道 | 终止 | |
SIGPOLL | 在SUSv4中被弃用 | 可轮训事件(poll) | 终止 | |
SIGPROF | 在SUSv4中被弃用 | 梗概时间超时(setitimer) | 终止 | |
SIGPWR | 依赖于系统的信号,用于不间断电影(UPS)的系统 | 电源失效/重启 | 终止/忽略 | |
SIGQUIT | Ctrl+|终端退出符 | 终止+core | ||
SIGSEGV | 进程进行了一次无效的内存引用(程序出错:访问一个未经初始化的指针) | 无效内存引用 | 终止+core | |
SIGSTKFLT | Linux定义:数序协处理器栈的故障 | 协处理器栈故障 | 终止 | |
SIGSTOP | 作业控制信号,停止一个进程 | 停止 | 停止进程 | |
SIGSYS | 早期版本的系统调用,现在不兼容 | 无效系统调用 | 终止+core | |
SIGTERM | kill(1)命令发送的系统默认终止信号,进程退出之前做好清理工作 | 终止 | 忽略 | |
SIGTHAW | Solais定义,被系统挂起的进程恢复时 | 检查单解冻 | 忽略 | |
SIGTHR | BSD线程库预留的信号 | 线程库内部使用 | 忽略 | |
SIGTRAP | 硬件故障 | 硬件故障 | 终止+core | |
SIGTSTP | 交互停止型号:Ctrl+z。 | 终端停止符 | 停止进程 | |
SIGTTIN | 后台进程试图读取其控制终端时,终端驱动产生 | 后台读控制tty | 停止进程 | |
SIGTTOU | 一个后台进程试图写其控制终端时,终端驱动产生次型号 | 后台写向控制tty | 停止进程 | |
SIGURG | 在网络连接上连接到带外的数据,可选择产生 | 紧急情况(套接字) | 忽略 | |
SIGUSR1 | 用户自定义信号 | 终止 | ||
SIGUSR2 | 用户自定义信号 | 终止 | ||
SIGVTALRM | setitimer(2)函数设置的虚拟间隔时间超时 | 虚拟时间闹钟(setitimer) | 终止 | |
SIGWAITING | 内核维护与每个终端或伪终端相关联窗口的大小 | 线程库内部使用 | 忽略 | |
SIGWINCH | 内核维持与每个终端或伪终端相关联窗口的大小 | 终端窗口大小改变 | 忽略 | |
SIGXCPU | 超过CPU限制(setrlimit) | 终止或终止+core | ||
SIGXFSZ | 超过文件长度限制(setrlimit) | 终止或终止+core | ||
SIGXRES | 超过资源控制 | 忽略 |
-
不可靠信号: 在早起版本中信号是不可靠的。信号可能会丢失,一个信号发生了,但进程可能一直不知道这点。
-
中断的系统调用:如果进程在执行一个低速系统(主要是I/O)调用而阻塞期间捕捉到一个信号,则系统调用被中断。该系统调用返回 errno =EINTR.
- 自动重启的系统调用:ioctl、read、write、readv、write、wait和waitpid.
- linux中:signal默认重启、sigaction可选。
-
可重入函数:在信号处理程序中保证调用安全的函数,这些函数是可充入并被称为是异步信号安全的。
-
可靠过程:信号由产生、发送、接受、处理过程。
- 内核接受信号后,通常在进程表设置一个标志。(发送、接受)
- 进程可以选择不接受信号(阻塞、屏蔽信号接受)
- 进程在屏蔽过程中可以改变对该信号的处理。
- 在阻塞过程中,如果多次发生多次。内核对这些信号进行排队
'产生-->发送-->接受-->处理
函数
signal :信号处理函数
#include <signal.h>
void (*signal(int signo,void (*func)(int)))(int);
--- '成功:返回以前的信号处理配置;出错:返回SIG_ERR'
# 使用方式
if(signal(SIGUSER1,sig_usr)SIG_ERR)
printf("can't catch SIGUSER1");
if(signal(SIGUSER2,sig_user)SIG_ERR)
printf("can't catch SIGUSER1");
-
参数:
- signo : 上表的信号常量
- (*func)(int) :信号处理程序
-
特点:
- signal注册一个信号及信号处理函数到内核
- exec函数新启动的进程不继承父进程的信号设置
kill、raise:
#include <signal.h>
int kill(pid_t pid,int signo);
int raise(int signo); '进程向自身发送信号'
-- '成功:0;出错:-1'
# 使用
raise(signo) = kill(gitpid(), signo);
- 参数:
- pid:
pid | 说明 |
---|---|
pid>0 | 将该信号发送给进程ID为pid的进程 |
pid0 | 将该信号发送给与发送进程属于同一进程组的所有进程,需权限 |
pid<0 | 将该信号发送给其它进程组ID等于pid的绝对值,需权限 |
pid-1 | 将该信号发送给有权限发送的所有进程 |
alarm:定时器
#include <unistd.h>
unsigned int alarm(unsiged int secods);
-- '0或以前设置的闹钟时间的余留秒数'
- 特点:
- 超时发送SIGALRM信号
- 尚未超时则返回剩余时间
pause:挂起进程直到捕捉到一个信号
#include <unistd.h>
void pause(void);
-- '-1,errno设置为EINTR'
- 特点:
- sleep函数:用 alarm和pause 实现的定时器。
- 执行了信号吹程序并从其返回时,pause才返回。
sigemptyset、sigfillset、sigaddset、sigdelset、sigismember:信号集设置
#include <signal.h>
int sigemptyset(sigset_t *secods);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signo);
int sigdelset(sigset_t *set,int signo);
-- '成功:0;出错:-1'
int sigismember(const sigset_t *set, int signo);
--'真:1;假:0'
- 特点
pid | 说明 |
---|---|
sigemptyset | 初始化set,并清除其中所有信号 |
sigfillset | 初始化set,使其包涵所有信号 |
sigaddset | 新增一个signo信号到set中 |
sigdelset | 删除一个signo信号到set中 |
sigismember | 定位signo是否在set中 |
sigprocmask:屏蔽信号集
#include <signal.h>
int sigprocmask(int how,const sigset_t *restrict set, sigset_t *restrict oset);
-- '成功:0;出错:-1'
-
参数:
- oset: 进程之前的屏蔽字
- how: 若set是空指针,则不改变该进程的信号屏蔽字,how无意义。
how | 说明 |
---|---|
SIG_BLOCK | 该进程新的信号屏蔽字是当前信号屏蔽字和set指向信号集的 并集,set包含了希望阻塞的附加信号 |
SIG_UNBLOCK | 该进程新的信号屏蔽字是当前信号屏蔽字和set所指向的信号屏蔽字的 交集。set包涵了希望解除阻塞的信号 |
SIG_SETMASK | 该进程新的信号屏蔽是指set所指向的值 |
sigpending:信号处理注册方法
#include <signal.h>
int sigpending(sigset_t *set);
--'成功:0;失败:-1'
-
特点:
- 类似于上面的pause和wait方法,等待信号唤醒。
sigaction : 信号处理注册方法
#include <signal.h>
int sigaction(int signo,const struct sigaction *restrict act, struct sigaction *restrict oact);
--'成功:0;失败:-1'
# sigaction结构
struct sigaction {
void (*sa_handler)(int); '信号处理函数'
sigset_t sa_mask; '屏蔽字信号集'
int sa_flags; '选项'
void (*sa_sigaction)(int,siginfo_t * , void *); '交替操作'
}
# sa_handler 函数
# 默认
void handler(int signo);
# sa_flags设置SA_SIGINFO
void handler(int signo, siginfo_t *info,void *context);
# siginfo_t 结构
struct siginfo {
int si_sigo; '信号数量'
int si_errno; 'if nonozero,errno value from <errno.h>'
int si_code; 'additional info (depends on signal)'
int si_pid; '信号发送的进程id'
int si_uid; '信号发送的进程user id'
int si_addr; '失败引起的地址'
int si_status; 'exit value or signal number'
union sigval si_value; '特殊的应用值'
....
}
-
参数:
-
sa_mask:在调用信号处理程序的时候,将被加入到进程的信号屏蔽字中。等待信号处理程序执行完成,则进程信号屏蔽字恢复。同一信号,一次处理一个
-
sa_flags:
-
选项 | 说明 |
---|---|
SA_INTERRUPT | 此信号终端的系统调用不自动重启 |
SA_NOCLDSTOP | 若signo是SIGCHLD,当子信号进程终止时,不产生此信号。 默认:当子进程终止时,仍旧产生次信号。设置:停止的进程继续运行时,不产生SIGCHLD信号。 |
SA_NOCLDWAIT | 若signo是SIGCHLD,则当调用进程的子进程终止时,不创建僵死进程。若调用进程随后调用wait,则阻塞到它所有子进程都终止,此时返回-1 |
SA_NODEFER | 当捕捉到此信号时,在执行其信号捕捉函数时,系统不自动阻塞此信号。 |
SA_ONSTACK | 若sigaltstack已声明了ige替换栈,则次信号递送给替换栈上的进程。 |
SA_RESETHAND | 信号处理函数的入口,将该信号的处理方式重置为SIG_DFL,并清除SA_SIGINFO标志。 |
SA_RESTART | 信号中断的系统调用自动重启 |
SA_SIGINFO | 信号处理程序会有信号的其它信息 |
sigsetjmp、siglongjmp: 跳转,类似goto
#include <setjmp.h>
int sigsetjmp(sigjmp_buf env,int savemask);
-- '直接调用,返回0;siglongjmp调用,返回非0'
void siglongjmp(sigjmp_buf env,int val);
# 使用方式
main(){
if(signal(SIGUSER1,sig_user1) SIG_ERR)
printf("signal error");
if(sigsetjmp(jmpbuf,1)){
printf("ending main:"); //siglongjmp调用
}
}
static void sig_usr1(int signo)
{
siglongjmp(jmpbuf,1);
}
- 特点:
- 原子操作:goto+sigprocmask
sigsuspend:原子操作:挂起进程,直到接收到信号集中的信号,执行信号处理函数,sigsuspend返回。
#include <signal.h>
int sigsuspend(const sigset_t *sigmask);
-- '返回:-1,并将errno设置为EINTR'
# 用法
sigset_t newmask,oldmask,waitmask
sigemptyset(&waitmask);
sigaddset(&waitmask,SIGUSER1);
sigemptyset(&newmask);
sigaddset(&newmask,SIGINT);
'屏蔽SIGINT信号'
if(sigprocmask(SIG_BLOCK,&newmask,&oldmask)<0){
printf("SIG_BLOCK error");
}
'挂起进程、等待用户进程'
if(sigsuspend(&waitmask)!=-1){
printf("sigsuspend error");
}
'将进程设置回去'
if(sigprocmask(SIG_BLOCK,&oldmask,NULL)<0){
printf("SIG_BLOCK error");
}
-
特点:
- 类似pause:挂起进程、等待某个信号。
- 子父进程之间的通信。
abort:使进程异常终止
#include <stdlib.h>
void abort(void);
sleep、nanosleep和clock_nanosleep
#include<unistd.h>
unsigned int sleep(unsigned int seconds);
--'0或未休眠完的秒数'
#include <time.h>
int nanosleep(const struct timespec *reqtp,struct timespec *remtp);
-- '若休眠到要求的时间,返回0;出错:-1'
int clock_nanosleep(clockid_t clock_id,int flags, const struct timesepc *reqtp, struct timespec *remtp);
-- '休眠要求的时间,返回0;出错,返回错误码'
-
特点:
- nanosleep:提供毫秒级
sigqueue:发送信号及信息,通过sigaction接受
#include <signal.h>
int sigqueue(pid_t pid,int signo,const union sigval value);
--'成功:0;出错:-1'
- 特点:
- sigaction 函数指定SA_SIGINFO标志。
- 子父进程之间的通信。