信号是软中断,包涵了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标志。
 - 子父进程之间的通信。
 
 
                    
                
                
            
        
浙公网安备 33010602011771号