信号

信号是软中断,包涵了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'
  • 特点:

    • 类似于上面的pausewait方法,等待信号唤醒。

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标志。
    • 子父进程之间的通信。

猜你喜欢

转载自my.oschina.net/u/2246410/blog/1801951