信号量

人们常用零和游戏的观点看世界,其实他们本不该这样。他们常常说:我比别人做的好,所以我就该发达。而在非零和游戏里,尽管你比别人做的好,你也可能和他一样潦倒。 —凯文·凯利《失控》

1. 概念

信号是事件发生时对进程的通知机制。有时可称之为软件中断。信号与硬件中断的相似之处在于打断了程序执行的正常流程。针对每个信号,都定义了一个唯一的(小)整数,从1开始顺序展开。信号分为两大类:

  • 一组用于内核向进程通知事件,构成传统或者标准信号。Linux标准信号的编号范围为1~31。
  • 另一组由实时信号构成。

    信号到达后,进程视具体信号可以执行以下操作:

  • 忽略信号,也就是说内核把信号丢弃,信号对进程没有产生任何影响(进程甚至不知道产生了信号)。

  • 终止(杀死)进程
  • 产生核心转储文件,同时终止进程,所谓的核心转储文件就是内存映像文件。
  • 停止进程,暂停进程的执行。
  • 重启之前暂停的进程

2. 信号类型

以下信号列表为不同硬件架构下对信号的编号;信号编号在架构上的差异在括号中予以说明:SPARC64(S)、HP/Compaq/DIgital Alpha(A)、MIPS(M)和HP PA-RISC(R)

名称信号值描述
SIGABRT 6终止进程,当进程调用abort()函数时,系统向进程发送该信号。
SIGALRM 14 实时定时器过期,经调用alarm()或setitimer()而设置的实时定时器一旦到期,内核将产生该信号。
SIGBUS 7(SAMP=10)内错误存访问,产生该信号(总线错误,bus error)即表示发生了某种内存访问错误。
SIGCHLD 17(SA=20,MP=18)终止或者停止子进程,当父进程的子进程终止(或因为调用了exit(),或者因为被信号杀死)时,(内核)将向父进程发送该信号。当父进程的某一子进程因收到信号而停止或恢复时,也可能会向父进程发送该信号。
SIGCONT 18(SA=19,M=25,P=26)若进程状态为停止状态,接受信号后则继续运行;将该信号发送给已停止的进程,进程将会恢复运行(即在之后的某个时间点重新获得调度)。当接受信号的进程当前不处于停止状态时,默认情况下将忽略该信号。
SIGEMT SAMP=7硬件错误
SIGFPE8算术异常;该信号因特定的算术错误而产生,比如除以0
SIGHUP1挂起进程
SIGILL4非法指令,如果进程试图执行非法(即格式不正确)的机器语言指令,系统将向进程发送该信号。
SIGINT2终端中断,当用户输入终端中断字符(通常为Control-C),终端驱动程序将发送该信号给前台进程组。
SIGIO29(SA=23,MP=22)I/O时可能产生,利用fcntl()系统调用,即特定类型(终端和套接字)的打开文件描述符发送的I/O事件产生该信号。
SIGKILL9必杀进程,处理器程序无法将其阻塞、忽略或者捕获,故而“一击必杀”
SIGPIPE13管道断开,当某一进程试图向管道、FIFO或套接字写入信息时,如果这些设备并无相应的阅读进程,那么系统将产生该信号。
SIGPROF27(M=29,P=21)性能分析定时器过期,由settimer()调用所设置的性能分析刚一过期,内核就将产生该信号。性能分析定时器用于记录进程所使用的CPU时间。
SIGQUIT3终端退出,当用户在键盘上键入退出字符(通常为Control+\)时,该信号将发往前台进程组。默认情况下,该信号终止进程,并生成可用于调试的核心转储文件。
SIGSEGV11无效的内存引用
SIGSTKFLT16(SAM=undef,P=36)协处理器栈错误
SIGSTOP19(SA=17,M=23,P=24)停止进程,这是一个必停信号,处理器程序无法将其阻塞、忽略或者捕获。
SIGSYS31(SAMP=12)无效的系统调用
SIGTERM15终止进程,这是用来终止进程的标准信号,也就是kill和killall命令所发送的默认信号。
SIGTRAP5跟踪/断开陷阱,该信号用来实现断点调试功能以及strace命令所执行的跟踪系统调用功能。
SIGTSTP20(SA=18,M=24,p=25)终端停止,当用户在键盘上输入挂起字符(通常是Control+Z)时,将发送该信号给前台进程组,使其停止运行。
SIGTTIN21(M=26,P=27)BG从终端读取,在作业控制shell下运行时,若后台进程组试图对终端进行read()操作,终端驱动程序则将向该进程组发送此信号。该信号默认停止进程。
SIGTTOU22(M=27,P=28)BG从终端写,与SIGTIN信号类似,该信号用于输出。
SIGURG23(SA=16,M=21,P=29)套接字上的紧急数据,系统发送该信号给一个进程,表示套接字上存在带外(也称作紧急)数据。
SIGUSR110(SA=30,MP=16)用户自定义信号1,该信号与SIGUSR2信号供程序员自定义使用。内核绝不会为进程产生这些信号。进程可以使用这些信号来相互通知事件的发生,或是彼此同步。
SIGUSR212(SA=31,MP=17)用户自定义信号2,与SIGUSR1等同。
SIGVTALRM26(M=28,P=20)虚拟定时器过期,调用setitimer()设置的虚拟定时器刚一到期,内核就会产生该信号。虚拟定时器记录的是进程在用户态使用的CPU时间。
SIGWINCH28(M=20,P=23)终端窗口尺寸发生变化
SIGXCPU24(M=30,P=33)突破对CPU时间的限制,当进程的CPU时间超过对应的资源限制时,将发送此信号给进程。
SIGXFSZ25(M=31,P=34)突破对文件大小的限制,当进程试图增大文件而突破对进程文件大小的资源限制时,name将发送此信号给进程。

3. 信号处理器

  1. 信号处理程序(也称为信号捕捉器)是当指定信号传递给进程视将会调用的一个函数。
  2. 调用信号处理程序,可能会随时打断主程序流程;内核代表进程来调用处理器程序,当处理器返回时,主程序会在处理器打断的位置恢复执行。流程图如下:

这里写图片描述

4. 信号掩码

内核会为每个进程维护一个信号掩码,即一组信号,并将阻塞其针对该进程的传递。如果将遭阻塞的信号发送给某进程,那么对该进程的传递将延后,直至从进程信号掩码中移除该信号,从而解除阻塞为止。

5. 代码示例

#include<stdio.h>
#include<signal.h>
static void handleSignal(int sig)
{
    printf("a ha\n");
}
int main(int argc, char *argv[])
{
    int i = 0;
    //处理控制台输入control+C命令;原来该信号直接回停止程序;现在改为输出a ha 语句。
    if(signal(SIGINT,handleSignal) == SIG_ERR) 
    {
        printf("signal handle fail!\n");
        exit(0);
    }
    for(i = 0 ; ; i++)
    {
        printf("i=%d\n",i);
        sleep(3);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值