《Unix环境高级编程》 总结 (七)

第十章 信号

1、信号概念

  • 信号为软中断,信号名字以SIG开始,信号定义在

2、LINUX下的信号

  • SIGABRT:调用函数abort产生,进程异常中止
  • SIGALRM:调用alarm()设置的定时器超时或者setitimer()设置的间隔时间超时
  • SIGBUS:硬件故障
  • SIGCHLD:子进程状态改变,老版本中可能为SIGCLD
  • SIGCONT:该信号发送给当前处于停止状态但需要继续运行的进程,如果进程在停止状态,则默认操作是继续执行,否则为忽略
  • SIGEMT:硬件故障
  • SIGFPE:算术异常,如除0,浮点溢出等
  • SIGHUP:?
  • SIGILL:进程已执行一条非法硬件指令
  • SIGINT:当在终端上按下Delete键(Ctrl+C)触发,将发送到前台进程组中的所有进程,此信号可被映射成终端任一字符;
  • SIGIO:指示一个异步IO事件,同SIGPOLL
  • SIGIOT:同SIGABRT
  • SIGKILL:不能被捕获,root用来杀死任一进程
  • SIGPIPE:管道的读进程结束后,写进程继续写时触发;或者类型为SOCK_STREAMR的socket断开连接后,进程继续写
  • SIGPOLL:同SIGIO
  • SIGPROF:当setitimer()设置的 profiling interval timer超时后触发
  • SIGPWR:与电源相关,如电源过低时,接收支电源过低信息的进程将向init发送该信号,从而由init处理停机操作
  • SIGQUIT:当按下退出键(Ctrl + )时触发,会发给所有前台进程组中的进程。该进程不仅停止前台进程组中的进程(同SIGINT),还要产生core文件
  • SIGSEGV:执行一个无效内存引发(如空指针)
  • SIGSTKFLT:?
  • SIGSTOP:用于停止进程,同SIGTSTP,但SIGSTOP不能被捕获
  • SIGSYS:指示一条无效的系统调用
  • SIGTERM:kill命令发出的系统默认中止信号,用户可以捕获,从而执行相应的处理工作(SIGKILL不能被捕获)
  • SIGTRAP:硬件故障
  • SIGTSTP:交互停止信号,按挂起键(Ctrl+Z)后发到前台进程组中的所有进程
  • SIGTTIN:后台进程组中的进程试图读其终端设备时触发;下面情形下不产生:a、进程忽略或者阻塞该信号;b、该进程组为孤儿进程组,此时出错,errno为EIO
  • SIGTTOUT:后台进程组中的进程试图写其终端设备时触发;下面情形下不产生:
    a、进程忽略或者阻塞该信号;
    b、该进程组为孤儿进程组,此时出错,errno为EIO;与SIGTIN不同,一个进程可以允许后台进程写终端,只有不允许写时才会出现该信号。除写外,下面函数也可以触发:tcsetattr、tcsendbreak、tcdrain、tcflush、tcflow、tcsetpgrp。
  • SIGURG:通知进程产生一个紧急情况,网络连接上传来带外数据也会触发
  • SIGUSR1:用户自定义信号
  • SIGUSR2:用户自定义信号
  • SIGVTALRM:由setitimer设置的虚拟间隔时间超时触发
  • SIGWINCH:终端窗口大小改变。进程可用ioctl改变终端窗口大小,此时内核将向前台进程组发送该信号
  • SIGXCPU:进程超过其软CPU时间限制时触发
  • SIGXFSZ:进程超过其软文件长度限制时触发

3、signal函数

函数定义如下:

#include <signal.h>
void (*signal(int signo,void (*func)(int)))(int);
    // 成功返回以前的信号处理配置,出错返回 SIG_ERR

注:signo为信号量;func为 SIG_IGN 时表示忽略,为 SIG_DFL 时表示默认,为函数指针则表示信号处理函数。该函数如下:
如定义:typedef void sigfunc(int);
则signal同下:sigfunc signal(int,sigfunc);

发送信号命令如下:
kill -USR1 7216 // 向进程7216发送信号 SIGUSR1
kill 7216 // 向进程7216发送信号 SIGTERM

执行exec后,将原先设置为要捕获的信号都改为默认动作,其它信号的状态则不变。
当一个进程fork一个子进程后,子进程将继承父进程的信号处理方式。

4、中断的系统调用

在执行低速系统调用时,该系统调用会被信号中断,该系统调用返回错误,errno设置为 EINTR ,此时要重新调用该系统调用,如下:
http://blog.csdn.net/benkaoya/article/details/17262053

5、可重入函数

进程收到信号后,会先中断正在执行的代码,去执行信号处理函数,信号处理函数完成后再返回。但信号处理函数中可能破坏正在执行的代码,但下面函数在信号处理函数中调用是安全的,即是可重入的或称异步信号安全的。这些函数也会在信号处理函数过程中阻塞任何引起不一致的信号的发送。可重入函数如下:

规则:在信号处理函数中调用可重入函数时,应在调用前保存 errno,调用后再恢复。

6、SIGCLD 信号 (同SIGCHLD)

子进程状态改变时,会向父进程发送该信号,如下:

http://www.cnblogs.com/wuchanming/p/4020463.html

7、kill 和 raise

kill将信号发给进程或进程组;raise将信号发给自己。相关定义如下:

#include <signal.h>
int kill(pid_t pid,int signo);
int raise(int signo);
    成功返回0.出错返回-1

注:raise(signo) == kill(getpid(),signo)
- pid > 0 : 向进程ID为pid的进程发送信号;
- pid = 0 :向与发送进程在同一进程组中的进程发送信号(发送进程要有向这些进程发送信号的权限),不包括系统进程集(内核进程和init);
- pid < 0 :向进程组ID为 |pid| 的进程组中的进程发送信号(发送进程要有向这些进程发送信号的权限),不包括系统进程集(内核进程和init);
- pid = -1 : 将信号发送给所有发送进程有权限发送信号的进程,不包括系统进程集(内核进程和init)。

权限规则:
a、超级用户无限制;
b、对于非超级用户,发送者的实际UID或有效UID必须等于接收者的实际UID或有效UID;如果支持 _POSIX_SAVED_IDS ,则检查接收者的保存设置用户ID;
c、特例:对于信号 SIGCONT ,可将它发给同一会话中的任一进程。

如果发送空信号(signo = 0),则用来检测进程是否存在。如果不存在返回-1,errno 为 ESRCH,但该操作不是原子操作,所以用处不大。

8、alarm 和 pause

alarm设置超时时间到后,收到信号 SIGALRM ,其默认操作为中止进程。定义如下:

#include <unistd.h>
unsigned int alarm(unsigned int seconds);
    // 返回0或以前设置的闹钟的剩余秒数

每个进程只能有一个闹钟,当已有一个时,重新设置会使用新的设置,返回剩余的秒数;当设置为0时,之前的闹钟被清除,但仍返回剩余秒数。
pause会挂起进程直到捕获到一个信号,如下:

#include <unistd.h>
int pause(void);
    // 返回-1,errno 设置为 EINTR

注:只有执行一个信号处理函数并返回后,pause才返回。

9、信号集

信号集相关函数如下:

#include <signal.h>
int sigemptyset(sigset_t *set);  // 清空信号集
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

10、信号屏蔽字:sigprocmask()

#include <signal.h>
int sigprocmask(int how, const sigset_t *restrict set, sigset_t *restrict oldset);
    // 成功返回0,失败返回-1

注:该方法可修改、查询当前进程的信号屏蔽字,如下:
- 当oldset不为NULL时,用来返回当前的信号屏蔽字,所要可设置set为NULL,oldset不为NULL,从而得到查询当前信号屏蔽字;
- 当set不为NULL时,用来设置信号屏蔽字,设置的方式由how指定,how取值如下:
a、SIG_BLOCK : 并集(将set中的信号添加到当前进程的信号屏蔽字)
b、SIG_UNBLOCK : 补集(从当前进程的信号屏蔽字中删除set中的信号)
c、SIG_SETMASK :直接设置为set

11、获取正在等待的信号集 : sigpending()

相关定义如下:

#include <signal.h>
int sigpending(sigset_t *set);
    // 成功返回0,失败返回-1

注:其中set存放被屏蔽字阻塞的信号集。被阻塞的信号集中如果有多个相同的,当消除屏蔽字后只会收到一个信号,其它相同信号舍弃。

12、函数 sigaction()

该函数用来检查或修改与指定信号相关联的处理动作。如下:

#include <signal.h>
int sigaction(int signum,const struct sigaction *act ,struct sigaction *oldact);
    // 成功返回0,失败返回-1

其中signum为信号ID;act不为NULL,则设置新的信号处理函数;oldact不为NULL,则得到之前的信号处理函数。struct sigaction 定义如下:

struct sigaction {
    void (*sa_handler)(int);
    void (*sa_sigaction)(int, siginfo_t *, void *);
    sigset_t sa_mask;
    int sa_flags;
    void (*sa_restorer)(void);
}

注:信号处理函数可以采用void (sa_handler)(int) 或 void (*sa_sigaction)(int, siginfo_t , void )。到底采用哪个要看sa_flags中是否设置了SA_SIGINFO位,如果设置了就采用void (*sa_sigaction)(int, siginfo_t , void *),此时可以向处理函数发送附加信息;默认情况下采用void (*sa_handler)(int),此时只能向处理函数发送信号的数值。
sa_handler此参数和signal()的参数handler相同,代表新的信号处理函数,其他意义请参考signal()。
sa_mask 用来设置在处理该信号时暂时将sa_mask 指定的信号集搁置。即在信号处理函数过程中,该信号集中的信号被加入信号屏蔽字,执行完后又恢复信号屏蔽字。
sa_restorer 此参数没有使用。

sa_flags 用来设置信号处理的其他相关操作,下列的数值可用。
- SA_RESETHAND:当调用信号处理函数时,将信号的处理函数重置为缺省值SIG_DFL
- SA_RESTART:如果信号中断了进程的某个系统调用,则系统自动启动该系统调用
- SA_NODEFER :一般情况下, 当信号处理函数运行时,内核将阻塞该给定信号。但是如果设置了
- SA_NODEFER标记, 那么在该信号处理函数运行时,内核将不会阻塞该信号。
sa_flags还可以设置其他标志,如下:

13、函数sigsetjmp() 和 siglongjmp()

要信号处理中使用,如下:

#include <setjmp.h>
int sigsetjmp(sigjmp_buf env,int savemask);
    // 直接调用返回0,从siglongjmp返回返回非0
void siglongjmp(sigjmp_buf end,int val);

注:与setjmp/longjmp的区别,如果savemask非0,则sigsetjmp会在env中保存当前信号屏蔽字,调用simlongjmp时会将保存的信号屏蔽字还原。

14、函数 sigsuspend()

该函数用来暂停进程,直到收到指定信号集之外的信号。如下:

#include <signal.h>
int sigsuspend(const sigset_t *sigmask);
    // 返回-1,errno设为 EINTR

注:进程执行到sigsuspend时,sigsuspend并不会立刻返回,进程处于TASK_INTERRUPTIBLE状态并立刻放弃CPU,等待UNBLOCK(mask之外的)信号的唤醒。进程在接收到UNBLOCK(mask之外)信号后,调用处理函数,然后把现在的信号集还原为原来的,sigsuspend返回,进程恢复执行。

15、abort 函数

该函数用来进程异常中止,如下:

#include <stdlib.h>
void abort(void);
    // 该函数无返回值

注:该函数将向调用进程发送信号 : SIGABRT ,同 raise(SIGABRT);
调用该函数不会返回(进程直接结束),abort不理会进程对该信号的阻塞和忽略,如果捕获该信号,并且信号处理函数没有调用了exit、_exit、_Exit、longjmp和siglongjmp,则信号处理函数返回后,abort终止该进程。

16、函数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 timespec *reqtp, struct timespec *remtp);
    // 休眠到要求的时间返回0,出错返回错误码

进程挂起,直到指定时间到达或者捕获到一个信号并从信号处理函数返回。
其中:reqtp为要设置的时间、remtp为返回时剩余时间(不关心可设为NULL),clock_id表示时钟类型,flags为0表示时间为相对时间(时间长度),为1表示绝对时间(休眠到某个特定时间)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值