精华内容
下载资源
问答
  • linux 信号

    2015-08-24 08:04:09
    linux 信号

    看了一些有关linux 信号相关的文章,做下记录:

    1.Linux信号(signal) 机制分析
    http://www.cnblogs.com/hoys/archive/2012/08/19/2646377.html
    2.在linux进程中的信号屏蔽
    http://blog.csdn.net/fjb2080/article/details/5174306







    展开全文
  • Linux 信号

    千次阅读 2015-10-14 19:56:03
    Linux 信号ref信号的概念最常见的信号就是在bash下启动一个程序按Ctrl+c 产生的硬件中断。如果CPU当前正在执行当前代码,则该进程的用户空间代码暂停,CPU就从用户态切换到内核态处理中断。BTW:Ctrl-c产生的信号...

    Linux 信号

    ref

    信号的概念

    最常见的信号就是在bash下启动一个程序按Ctrl+c 产生的硬件中断。如果CPU当前正在执行当前代码,则该进程的用户空间代码暂停,CPU就从用户态切换到内核态处理中断。

    BTWCtrl-c产生的信号只能是前台进程发送,有些通过命令后+&放到后台运行,这样不必等待进程结束就可以接受新的命令,shell就可以在一个前台进程的同时跑多个后台进程,信号相对于进程的控制流程来说是异步的。

    系统定义的信号列表

    luyunchengdeMacBook-Pro:~ luyuncheng$ kill -l
    1) SIGHUP    2) SIGINT   3) SIGQUIT  4) SIGILL
    5) SIGTRAP   6) SIGABRT  7) SIGEMT   8) SIGFPE
    9) SIGKILL  10) SIGBUS  11) SIGSEGV 12) SIGSYS
    13) SIGPIPE 14) SIGALRM 15) SIGTERM 16) SIGURG
    17) SIGSTOP 18) SIGTSTP 19) SIGCONT 20) SIGCHLD
    21) SIGTTIN 22) SIGTTOU 23) SIGIO   24) SIGXCPU
    25) SIGXFSZ 26) SIGVTALRM   27) SIGPROF 28) SIGWINCH
    29) SIGINFO 30) SIGUSR1 31) SIGUSR2
    

    这些编号和宏定义以及介绍在usr/include/signal.h可以找到。

    ./asm-generic/signal.h:10:#define SIGHUP         1
    ./x86_64-linux-gnu/bits/signum.h:33:#define SIGHUP      1   /* Hangup (POSIX).  */
    ./x86_64-linux-gnu/asm/signal.h:19:#define SIGHUP        1
    

    在编号34以上为实时信号,34以下为非实时信号。

    Signal Value Action Comment
    SIGHUP 1 Term Hangup detected on controlling terminal or death of controlling process
    SIGINT 2 Term Interrupt from keyboard
    SIGQUIT 3 Core Quit from keyboard
    SIGILL 4 Core Illegal Instruction
    SIGABRT 6 Core Abort signal from abort(3)
    SIGFPE 8 Core Floating point exception
    SIGKILL 9 Term Kill signal
    SIGSEGV 11 Core Invalid memory reference
    SIGPIPE 13 Term Broken pipe: write to pipe with no read
    SIGALRM 14 Term Timer signal from alarm(2)
    SIGTERM 15 Term Termination signal
    SIGUSR1 30,10,16 Term User-defined signal 1
    SIGUSR2 31,12,17 Term User-defined signal 2
    SIGCHLD 20,17,18 Ign Child stopped or terminated
    SIGCONT 19,18,25 ~~ Continue if stopped
    SIGSTOP 17,19,23 Stop Stop process
    SIGTSTP 18,20,24 Stop Stop typed at tty
    SIGTTIN 21,21,26 Stop tty input for background process
    SIGTTOU 22,22,27 Stop tty output for background process

    其中Action中,Term表示终止当前进程,Core表示终止当前进程并且CoreDump,Ign表示忽略信号,Stop表示停止当前进程,Cont表示继续执行先前停止的进程。

    产生信号的条件有:

    1. bash按下时,终端会发送信号给前台,Ctrl-C产生SIGINT信号,Ctrl-\产生SIGQUIT信号,Ctrl-Z产生SIGTSTP信号,上述信号使得进程停止。
    2. 硬件异常信号,条件由硬件检测到并通知内核,然后内核向当前进程发送信号。例如执行了除以0的指令,CPU的运算单元会产生异常,内核将这个异常解释为SIGFPE信号发送给进程。再比如当前进程访问了非法内存地址,,MMU会产生异常,内核将这个异常解释为SIGSEGV信号发送给进程。
    3. 一个进程调用kill(2)函数可以发送信号给另一个进程。
    4. 可以用kill(1)命令发送信号给某个进程,kill(1)命令也是调用kill(2)函数实现的,如果不明确指定信号则发送SIGTERM信号,该信号的默认处理动作是终止进程。
    5. 当内核检测到某种软件条件发生时也可以通过信号通知进程,例如闹钟超时产生SIGALRM信号,向读端已关闭的管道写数据时产生SIGPIPE信号。

    信号的产生

    终端产生信号

    前面说Term是使终止当前进程,Core表示终止当前进程并有CoreDump。CoreDump是指当一个进程终止时,就把进程的用户态中内存数据保存到磁盘里面,文件名字是core,这个就是CoreDump。这种方法主要是用于debug,比方说程序跑的时候有错误的时候,异常终止,那么事后就可以通过core文件找bug。一个进程允许产生的core文件大小由PCB中ResourceLimit这个变量决定。默认不让产生core文件,可以用ulimit 改变限制。

    $ ulimit -c 1024 //改变Resource Limit 大小为1024K
    

    然后跑程序的时候Ctrl+\ 就会产生core dumped

    函数产生信号

    #include<stdio.h>
    //t1.c
    int main()
    {
        while(1){}
        return 0;
    }
    

    调用kill函数 &后台运行

    root@ubuntu:~/Workspace/luyuncheng/ex_c++# ./t1 &
    [1] 12137
    root@ubuntu:~/Workspace/luyuncheng/ex_c++# kill -SIGSEGV 12137
    root@ubuntu:~/Workspace/luyuncheng/ex_c++#  回车
    [1]+  Segmentation fault      (core dumped) ./t1
    

    &是后台运行,12137是进程的pid,之所以要回车才显示Segmentation fault,因为在12137进程终止掉之前已经回到了Shell提示符等待用户输入下一条命令,Shell不希望Segmentation fault信息和用户的输入交错在一起,所以等用户输入命令之后才显示。指定某种信号的kill命令可以有多种写法,上面的命令还可以写成kill -SEGV 12137kill -11 7940,11是信号SIGSEGV的编号。以往遇到的段错误都是由非法内存访问产生的,而这个程序本身没错,给它发SIGSEGV也能产生段错误。

    kill函数就是給指定进程发送信号,raise就是給当前进程发送指定的信号(自己发自己)
    函数原型: 成功返回0,错误返回-1

    #include <signal.h>
    int kill(pid_t pid, int signo);//給pid发送signo信号
    int raise(int signo);//给自己发signo信号
    void abort(void);//給自己发SIGABRT信号终止
    

    软件产生的条件信号

    #include <unistd.h>
    unsigned int alarm(unsigned int seconds);
    

    alarm函数就是告诉内核seconds秒后給进程发SIGALRM信号,这个信号的默认处理动作时终止当前进程。这个函数有一个unsigned int的返回值,表示与设定的时间还余下的秒数。如果传入的值为0,表示取消当前设定的alarm。

    信号的阻塞

    我们称执行信号的处理动作称为传递(delivery),信号从产生到传递之间的状态,称为pending。进程可以选择阻塞(Block)某个信号。被阻塞的信号产生时将保持在pending的状态,直到阻塞解除后,执行delivery状态。note:阻塞和忽略是不同的,信号被阻塞不会传递,但是忽略是在delivery之后可选的一种处理动作。信号在内核中的表示可以看作是:

    signal.internal
    每个信号都有两个标志位分别表示阻塞和未决,还有一个函数指针表示处理动作。信号产生时,内核在进程控制块中设置该信号的未决标志,直到信号递达才清除该标志。在上图的例子中,
    1. SIGHUP信号未阻塞也未产生过,当它递达时执行默认处理动作。
    2. SIGINT信号产生过,但正在被阻塞,所以暂时不能递达。虽然它的处理动作是忽略,但在没有解除阻塞之前不能忽略这个信号,因为进程仍有机会改变处理动作之后再解除阻塞。
    3. SIGQUIT信号未产生过,一旦产生SIGQUIT信号将被阻塞,它的处理动作是用户自定义函数sighandler。

        如果在进程解除对某信号的阻塞之前这种信号产生过多次,将如何处理?POSIX.1允许系统递送该信号一次或多次。Linux是这样实现的:常规信号在递达之前产生多次只计一次,而实时信号在递达之前产生多次可以依次放在一个队列里。本章不讨论实时信号。从上图来看,每个信号只有一个bit的未决标志,非0即1,不记录该信号产生了多少次,阻塞标志也是这样表示的。因此,未决和阻塞标志可以用相同的数据类型sigset_t来存储,sigset_t称为信号集,这个类型可以表示每个信号的“有效”或“无效”状态,在阻塞信号集中“有效”和“无效”的含义是该信号是否被阻塞,而在未决信号集中“有效”和“无效”的含义是该信号是否处于未决状态。下一节将详细介绍信号集的各种操作。阻塞信号集也叫做当前进程的信号屏蔽字(Signal Mask),这里的“屏蔽”应该理解为阻塞而不是忽略。
        

    信号集操作函数

    sigset_t类型对于每种信号用一个bit表示“有效”或“无效”状态,至于这个类型内部如何存储这些bit则依赖于系统实现,从使用者的角度是不必关心的,使用者只能调用以下函数来操作sigset_t变量,而不应该对它的内部数据做任何解释,比如用printf直接打印sigset_t变量是没有意义的。

    #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);
    int sigismember(const sigset_t *set, int signo);
    

    函数sigemptyset初始化set所指向的信号集,使其中所有信号的对应bit清零,表示该信号集不包含任何有效信号。函数sigfillset初始化set所指向的信号集,使其中所有信号的对应bit置位,表示该信号集的有效信号包括系统支持的所有信号。注意,在使用sigset_t类型的变量之前,一定要调用sigemptysetsigfillset做初始化,使信号集处于确定的状态。初始化sigset_t变量之后就可以在调用sigaddsetsigdelset在该信号集中添加或删除某种有效信号。这四个函数都是成功返回0,出错返回-1。sigismember是一个布尔函数,用于判断一个信号集的有效信号中是否包含某种信号,若包含则返回1,不包含则返回0,出错返回-1。

    sigprocmask

    调用函数sigprocmask可以读取或更改进程的信号屏蔽字。

    #include <signal.h>
    int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
    

    返回值:若成功则为0,若出错则为-1
    如果oset是非空指针,则读取进程的当前信号屏蔽字通过oset参数传出。如果set是非空指针,则更改进程的信号屏蔽字,参数how指示如何更改。如果oset和set都是非空指针,则先将原来的信号屏蔽字备份到oset里,然后根据set和how参数更改信号屏蔽字。假设当前的信号屏蔽字为mask,下表说明了how参数的可选值。
    how参数的含义:

    HOW Comment
    SIG_BLOCK set包含了我们希望添加到当前信号屏蔽字的信号,相当于`mask=mask
    SIG_UNBLOCK set包含了我们希望从当前信号屏蔽字中解除阻塞的信号,相当于mask=mask&~set
    SIG_SETMASK 设置当前信号屏蔽字为set所指向的值,相当于mask=set

    如果调用sigprocmask解除了对当前若干个未决信号的阻塞,则在sigprocmask返回前,至少将其中一个信号递达。

    sigpending

    #include <signal.h>
    int sigpending(sigset_t *set);
    

    sigpending读取当前进程的未决信号集,通过set参数传出。调用成功则返回0,出错则返回-1。

    例子:

    #include <signal.h>
    #include <stdio.h>
    #include <unistd.h>
    
    void printsigset(const sigset_t *set)
    {
        int i;
        for (i = 1; i < 32; i++)
            if (sigismember(set, i) == 1)
                putchar('1');
            else
                putchar('0');
        puts("");
    }
    
    int main(void)
    {
        sigset_t s, p;
        sigemptyset(&s);
        sigaddset(&s, SIGINT);
        sigprocmask(SIG_BLOCK, &s, NULL);
        while (1) {
            sigpending(&p);
            printsigset(&p);
            sleep(1);
        }
        return 0;
    }
    

    程序运行时,每秒钟把各信号的未决状态打印一遍,由于我们阻塞了SIGINT信号,按Ctrl-C将会使SIGINT信号处于未决状态,按Ctrl-\仍然可以终止程序,因为SIGQUIT信号没有阻塞。

    $ ./a.out 
    0000000000000000000000000000000
    0000000000000000000000000000000(这时按Ctrl-C)
    0100000000000000000000000000000
    0100000000000000000000000000000(这时按Ctrl-\)
    Quit (core dumped)
    

    捕捉信号

    内核对于信号的捕捉

    如果信号的处理动作是用户自定义函数,在信号递达时就调用这个函数,这称为捕捉信号。由于信号处理函数的代码是在用户空间的,处理过程比较复杂,举例如下:
    1. 用户程序注册了SIGQUIT信号的处理函数sighandler。
    2. 当前正在执行main函数,这时发生中断或异常切换到内核态。
    3. 在中断处理完毕后要返回用户态的main函数之前检查到有信号SIGQUIT递达。
    4. 内核决定返回用户态后不是恢复main函数的上下文继续执行,而是执行sighandler函数,sighandler和main函数使用不同的堆栈空间,它们之间不存在调用和被调用的关系,是两个独立的控制流程。
    5. sighandler函数返回后自动执行特殊的系统调用sigreturn再次进入内核态。
    6. 如果没有新的信号要递达,这次再返回用户态就是恢复main函数的上下文继续执行了。
    信号的捕捉: [ref:Understanding the Linux Kernel. 3. Daniel P. Bovet和Marco Cesati.]
    signalcatch

    sigaction

    #include <signal.h>
    int sigaction(int signo, const struct sigaction *act, struct sigaction *oact);
    

    sigaction函数可以读取和修改与指定信号相关联的处理动作。调用成功则返回0,出错则返回-1。signo是指定信号的编号。若act指针非空,则根据act修改该信号的处理动作。若oact指针非空,则通过oact传出该信号原来的处理动作。act和oact指向sigaction结构体:

    struct sigaction {
       void      (*sa_handler)(int);   /* addr of signal handler, */
                                           /* or SIG_IGN, or SIG_DFL */
       sigset_t sa_mask;               /* additional signals to block */
       int      sa_flags;              /* signal options, Figure 10.16 */
    
       /* alternate handler */
       void     (*sa_sigaction)(int, siginfo_t *, void *);
    };  
    

    sa_handler赋值为常数SIG_IGN传给sigaction表示忽略信号,赋值为常数SIG_DFL表示执行系统默认动作,赋值为一个函数指针表示用自定义函数捕捉信号,或者说向内核注册了一个信号处理函数,该函数返回值为void,可以带一个int参数,通过参数可以得知当前信号的编号,这样就可以用同一个函数处理多种信号。显然,这也是一个回调函数,不是被main函数调用,而是被系统所调用。

    当某个信号的处理函数被调用时,内核自动将当前信号加入进程的信号屏蔽字,当信号处理函数返回时自动恢复原来的信号屏蔽字,这样就保证了在处理某个信号时,如果这种信号再次产生,那么它会被阻塞到当前处理结束为止。如果在调用信号处理函数时,除了当前信号被自动屏蔽之外,还希望自动屏蔽另外一些信号,则用sa_mask字段说明这些需要额外屏蔽的信号,当信号处理函数返回时自动恢复原来的信号屏蔽字。

    sa_flags字段包含一些选项,本章的代码都把sa_flags设为0,sa_sigaction是实时信号的处理函数,本章不详细解释这两个字段,有兴趣的读者参考[Advanced Programming in the UNIX Environment. 2. W. Richard Stevens和Stephen A. Rago.]

    pause

    #include <unistd.h>
    int pause(void);
    

    pause函数使调用进程挂起直到有信号递达。如果信号的处理动作是终止进程,则进程终止,pause函数没有机会返回;如果信号的处理动作是忽略,则进程继续处于挂起状态,pause不返回;如果信号的处理动作是捕捉,则调用了信号处理函数之后pause返回-1,errno设置为EINTR,所以pause只有出错的返回值(想想以前还学过什么函数只有出错返回值?)。错误码EINTR表示“被信号中断”。

    下面我们用alarm和pause实现sleep(3)函数,称为mysleep。
    例子:mysleep

    #include <unistd.h>
    #include <signal.h>
    #include <stdio.h>
    
    void sig_alrm(int signo)
    {
        /* nothing to do */
    }
    
    unsigned int mysleep(unsigned int nsecs)
    {
        struct sigaction newact, oldact;
        unsigned int unslept;
    
        newact.sa_handler = sig_alrm;
        sigemptyset(&newact.sa_mask);
        newact.sa_flags = 0;
        sigaction(SIGALRM, &newact, &oldact);
    
        alarm(nsecs);
        pause();
    
        unslept = alarm(0);
        sigaction(SIGALRM, &oldact, NULL);
    
        return unslept;
    }
    
    int main(void)
    {
        while(1){
            mysleep(2);
            printf("Two seconds passed\n");
        }
        return 0;
    }
    

    1. main函数调用mysleep函数,后者调用sigaction注册了SIGALRM信号的处理函数sig_alrm
    2. 调用alarm(nsecs)设定闹钟。
    3. 调用pause等待,内核切换到别的进程运行。
    4. nsecs秒之后,闹钟超时,内核发SIGALRM给这个进程。
    5. 从内核态返回这个进程的用户态之前处理未决信号,发现有SIGALRM信号,其处理函数是sig_alrm
    6. 切换到用户态执行sig_alrm函数,进入sig_alrm函数时SIGALRM信号被自动屏蔽,从sig_alrm函数返回时SIGALRM信号自动解除屏蔽。然后自动执行系统调用sigreturn再次进入内核,再返回用户态继续执行进程的主控制流程(main函数调用的mysleep函数)。
    7. pause函数返回-1,然后调用alarm(0)取消闹钟,调用sigaction恢复SIGALRM信号以前的处理动作。

    可重入函数

    当捕捉到信号时,不论进程的主控制流程当前执行到哪儿,都会先跳到信号处理函数中执行,从信号处理函数返回后再继续执行主控制流程。信号处理函数是一个单独的控制流程,因为它和主控制流程是异步的,二者不存在调用和被调用的关系,并且使用不同的堆栈空间。引入了信号处理函数使得一个进程具有多个控制流程,如果这些控制流程访问相同的全局资源(全局变量、硬件资源等),就有可能出现冲突,如下面的例子所示。

    不可重入函数:
    signal.reentrancy

    main函数调用insert函数向一个链表head中插入节点node1,插入操作分为两步,刚做完第一步的时候,因为硬件中断使进程切换到内核,再次回用户态之前检查到有信号待处理,于是切换到sighandler函数,sighandler也调用insert函数向同一个链表head中插入节点node2,插入操作的两步都做完之后从sighandler返回内核态,再次回到用户态就从main函数调用的insert函数中继续往下执行,先前做第一步之后被打断,现在继续做完第二步。结果是,main函数和sighandler先后向链表中插入两个节点,而最后只有一个节点真正插入链表中了。

    像上例这样,insert函数被不同的控制流程调用,有可能在第一次调用还没返回时就再次进入该函数,这称为重入,insert函数访问一个全局链表,有可能因为重入而造成错乱,像这样的函数称为不可重入函数,反之,如果一个函数只访问自己的局部变量或参数,则称为可重入(Reentrant)函数。想一下,为什么两个不同的控制流程调用同一个函数,访问它的同一个局部变量或参数就不会造成错乱?

    如果一个函数符合以下条件之一则是不可重入的:

    1. 调用了malloc或free,因为malloc也是用全局链表来管理堆的。
    2. 调用了标准I/O库函数。标准I/O库的很多实现都以不可重入的方式使用全局数据结构。

    sig_atomic_t类型与volatile限定符

    在上面的例子中,main和sighandler都调用insert函数则有可能出现链表的错乱,其根本原因在于,对全局链表的插入操作要分两步完成,不是一个原子操作,假如这两步操作必定会一起做完,中间不可能被打断,就不会出现错乱了。下一节线程会讲到如何保证一个代码段以原子操作完成。

    现在想一下,如果对全局数据的访问只有一行代码,是不是原子操作呢?比如,main和sighandler都对一个全局变量赋值,会不会出现错乱呢?比如下面的程序:

    long long a;
    int main(void)
    {
        a=5;
        return 0;
    }
    

    带调试信息编译,然后带源代码反汇编:

    $ gcc main.c -g
    $ objdump -dS a.out
    

    其中main函数的指令中有:

        a=5;
     8048352:       c7 05 50 95 04 08 05    movl   $0x5,0x8049550
     8048359:       00 00 00 
     804835c:       c7 05 54 95 04 08 00    movl   $0x0,0x8049554
     8048363:       00 00 00
    

    虽然C代码只有一行,但是在32位机上对一个64位的long long变量赋值需要两条指令完成,因此不是原子操作。同样地,读取这个变量到寄存器需要两个32位寄存器才放得下,也需要两条指令,不是原子操作。请读者设想一种时序,main和sighandler都对这个变量a赋值,最后变量a的值发生错乱。

    如果上述程序在64位机上编译执行,则有可能用一条指令完成赋值,因而是原子操作。如果a是32位的int变量,在32位机上赋值是原子操作,在16位机上就不是。如果在程序中需要使用一个变量,要保证对它的读写都是原子操作,应该采用什么类型呢?为了解决这些平台相关的问题,C标准定义了一个类型sig_atomic_t,在不同平台的C语言库中取不同的类型,例如在32位机上定义sig_atomic_t为int类型。

    在使用sig_atomic_t类型的变量时,还需要注意另一个问题。看如下的例子:

    #include <signal.h>
    
    sig_atomic_t a=0;
    int main(void)
    {
        /* register a sighandler */
        while(!a); /* wait until a changes in sighandler */
        /* do something after signal arrives */
        return 0;
    }
    

    为了简洁,这里只写了一个代码框架来说明问题。在main函数中首先要注册某个信号的处理函数sighandler,然后在一个while死循环中等待信号发生,如果有信号递达则执行sighandler,在sighandler中将a改为1,这样再次回到main函数时就可以退出while循环,执行后续处理。用上面的方法编译和反汇编这个程序,在main函数的指令中有:

    /* register a sighandler */
        while(!a); /* wait until a changes in sighandler */
     8048352:       a1 3c 95 04 08          mov    0x804953c,%eax
     8048357:       85 c0                   test   %eax,%eax
     8048359:       74 f7                   je     8048352 <main+0xe>
    

    将全局变量a从内存读到eax寄存器,对eax和eax做AND运算,若结果为0则跳回循环开头,再次从内存读变量a的值,可见这三条指令等价于C代码的while(!a);循环。如果在编译时加了优化选项,例如:

    $ gcc main.c -O1 -g
    $ objdump -dS a.out
    

    则main函数的指令中有:

    8048352:       83 3d 3c 95 04 08 00    cmpl   $0x0,0x804953c
        /* register a sighandler */
        while(!a); /* wait until a changes in sighandler */
     8048359:       74 fe                   je     8048359 <main+0x15>
    

    第一条指令将全局变量a的内存单元直接和0比较,如果相等,则第二条指令成了一个死循环,注意,这是一个真正的死循环:即使sighandler将a改为1,只要没有影响Zero标志位,回到main函数后仍然死在第二条指令上,因为不会再次从内存读取变量a的值。

    是编译器优化得有错误吗?不是的。设想一下,如果程序只有单一的执行流程,只要当前执行流程没有改变a的值,a的值就没有理由会变,不需要反复从内存读取,因此上面的两条指令和while(!a);循环是等价的,并且优化之后省去了每次循环读内存的操作,效率非常高。所以不能说编译器做错了,只能说编译器无法识别程序中存在多个执行流程。之所以程序中存在多个执行流程,是因为调用了特定平台上的特定库函数,比如sigactionpthread_create,这些不是C语言本身的规范,不归编译器管,程序员应该自己处理这些问题。C语言提供了volatile限定符,如果将上述变量定义为volatile sig_atomic_t a=0;那么即使指定了优化选项,编译器也不会优化掉对变量a内存单元的读写。

    对于程序中存在多个执行流程访问同一全局变量的情况,volatile限定符是必要的,此外,虽然程序只有单一的执行流程,但是变量属于以下情况之一的,也需要volatile限定:

    1. 变量的内存单元中的数据不需要写操作就可以自己发生变化,每次读上来的值都可能不一样
    2. 即使多次向变量的内存单元中写数据,只写不读,也并不是在做无用功,而是有特殊意义的

    什么样的内存单元会具有这样的特性呢?肯定不是普通的内存,而是映射到内存地址空间的硬件寄存器,例如串口的接收寄存器属于上述第一种情况,而发送寄存器属于上述第二种情况。

    sig_atomic_t类型的变量应该总是加上volatile限定符,因为要使用sig_atomic_t类型的理由也正是要加volatile限定符的理由。

    竞态条件与sigsuspend函数

    重新看到mysleep的代码:
    设想这样的时序:

    1. 注册SIGALRM信号的处理函数。
    2. 调用alarm(nsecs)设定闹钟。
    3. 内核调度优先级更高的进程取代当前进程执行,并且优先级更高的进程有很多个,每个都要执行很长时间
    4. nsecs秒钟之后闹钟超时了,内核发送SIGALRM信号给这个进程,处于未决状态。
    5. 优先级更高的进程执行完了,内核要调度回这个进程执行。SIGALRM信号递达,执行处理函数sig_alrm之后再次进入内核。
    6. 返回这个进程的主控制流程,alarm(nsecs)返回,调用pause()挂起等待。
    7. 可是SIGALRM信号已经处理完了,还等待什么呢?

    出现这个问题的根本原因是系统运行的时序(Timing)并不像我们写程序时所设想的那样。虽然alarm(nsecs)紧接着的下一行就是pause(),但是无法保证pause()一定会在调用alarm(nsecs)之后的nsecs秒之内被调用。由于异步事件在任何时候都有可能发生(这里的异步事件指出现更高优先级的进程),如果我们写程序时考虑不周密,就可能由于时序问题而导致错误,这叫做竞态条件(Race Condition)。

    如何解决上述问题呢?读者可能会想到,在调用pause之前屏蔽SIGALRM信号使它不能提前递达就可以了。看看以下方法可行吗?

    1. 屏蔽SIGALRM信号;
    2. alarm(nsecs);
    3. 解除对SIGALRM信号的屏蔽;
    4. pause();

    从解除信号屏蔽到调用pause之间存在间隙,SIGALRM仍有可能在这个间隙递达。要消除这个间隙,我们把解除屏蔽移到pause后面可以吗?

    1. 屏蔽SIGALRM信号;
    2. alarm(nsecs);
    3. pause();
    4. 解除对SIGALRM信号的屏蔽;

    这样更不行了,还没有解除屏蔽就调用pause,pause根本不可能等到SIGALRM信号。要是“解除信号屏蔽”和“挂起等待信号”这两步能合并成一个原子操作就好了,这正是sigsuspend函数的功能。sigsuspend包含了pause的挂起等待功能,同时解决了竞态条件的问题,在对时序要求严格的场合下都应该调用sigsuspend而不是pause。

    #include <signal.h>
    
    int sigsuspend(const sigset_t *sigmask);
    

    和pause一样,sigsuspend没有成功返回值,只有执行了一个信号处理函数之后sigsuspend才返回,返回值为-1,errno设置为EINTR。

    调用sigsuspend时,进程的信号屏蔽字由sigmask参数指定,可以通过指定sigmask来临时解除对某个信号的屏蔽,然后挂起等待,当sigsuspend返回时,进程的信号屏蔽字恢复为原来的值,如果原来对该信号是屏蔽的,从sigsuspend返回后仍然是屏蔽的。

    以下用sigsuspend重新实现mysleep函数:

    unsigned int mysleep(unsigned int nsecs)
    {
        struct sigaction    newact, oldact;
        sigset_t            newmask, oldmask, suspmask;
        unsigned int        unslept;
    
        /* set our handler, save previous information */
        newact.sa_handler = sig_alrm;
        sigemptyset(&newact.sa_mask);
        newact.sa_flags = 0;
        sigaction(SIGALRM, &newact, &oldact);
    
        /* block SIGALRM and save current signal mask */
        sigemptyset(&newmask);
        sigaddset(&newmask, SIGALRM);
        sigprocmask(SIG_BLOCK, &newmask, &oldmask);
    
        alarm(nsecs);
    
        suspmask = oldmask;
        sigdelset(&suspmask, SIGALRM);    /* make sure SIGALRM isn't blocked */
        sigsuspend(&suspmask);            /* wait for any signal to be caught */
    
        /* some signal has been caught,   SIGALRM is now blocked */
    
        unslept = alarm(0);
        sigaction(SIGALRM, &oldact, NULL);  /* reset previous action */
    
        /* reset signal mask, which unblocks SIGALRM */
        sigprocmask(SIG_SETMASK, &oldmask, NULL);
        return(unslept);
    }
    

    如果在调用mysleep函数时SIGALRM信号没有屏蔽:

    1. 调用sigprocmask(SIG_BLOCK, &newmask, &oldmask);时屏蔽SIGALRM。
    2. 调用sigsuspend(&suspmask);时解除对SIGALRM的屏蔽,然后挂起等待待。
    3. SIGALRM递达后suspend返回,自动恢复原来的屏蔽字,也就是再次屏蔽SIGALRM。
    4. 调用sigprocmask(SIG_SETMASK, &oldmask, NULL);时再次解除对SIGALRM的屏蔽。

    关于SIGCHLD信号

    进程一章讲过用wait和waitpid函数清理僵尸进程,父进程可以阻塞等待子进程结束,也可以非阻塞地查询是否有子进程结束等待清理(也就是轮询的方式)。采用第一种方式,父进程阻塞了就不能处理自己的工作了;采用第二种方式,父进程在处理自己的工作的同时还要记得时不时地轮询一下,程序实现复杂。

    其实,子进程在终止时会给父进程发SIGCHLD信号,该信号的默认处理动作是忽略,父进程可以自定义SIGCHLD信号的处理函数,这样父进程只需专心处理自己的工作,不必关心子进程了,子进程终止时会通知父进程,父进程在信号处理函数中调用wait清理子进程即可。

    请编写一个程序完成以下功能:父进程fork出子进程,子进程调用exit(2)终止,父进程自定义SIGCHLD信号的处理函数,在其中调用wait获得子进程的退出状态并打印。

    事实上,由于UNIX的历史原因,要想不产生僵尸进程还有另外一种办法:父进程调用sigaction将SIGCHLD的处理动作置为SIG_IGN,这样fork出来的子进程在终止时会自动清理掉,不会产生僵尸进程,也不会通知父进程。系统默认的忽略动作和用户用sigaction函数自定义的忽略通常是没有区别的,但这是一个特例。此方法对于Linux可用,但不保证在其它UNIX系统上都可用。请编写程序验证这样做不会产生僵尸进程。

    展开全文
  • linux信号

    千次阅读 2011-06-10 09:48:00
    不过可以捕获这个信号,比如wget能捕获SIGHUP信号,并忽略它,这样就算退出了Linux登录,wget也 能继续下载。此外,对于与终端脱离关系的守护进程,这个信号用于通知它重新读取配置文件。 2) SIGINT程序终止...
    $ kill -l1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR213) SIGPIPE 14) SIGALRM 15) SIGTERM 16) SIGSTKFLT 17) SIGCHLD18) SIGCONT 19) SIGSTOP 20) SIGTSTP 21) SIGTTIN22) SIGTTOU 23)
     SIGURG 24) SIGXCPU 25) SIGXFSZ26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO30) SIGPWR 31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+136) SIGRTMIN+2 37) SIGRTMIN+3 38) SIGRTMIN+4 39) SIGRTMIN+540) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8 43) SIGRTMIN+944) SIGRTMIN+10
     45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+1348) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-1352) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-956) SIGRTMAX-8 57) SIGRTMAX-7 58) SIGRTMAX-6 59) SIGRTMAX-560) SIGRTMAX-4 61) SIGRTMAX-3
     62) SIGRTMAX-2 63) SIGRTMAX-164) SIGRTMAX列表中,编号为1 ~ 31的信号为传统UNIX支持的信号,是不可靠信号(非实时的),编号为32 ~ 63的信号是后来扩充的,称做可靠信号(实时信号)。不可靠信号和可靠信号的区别在于前者不支持排队,可能会造成信号丢失,而后者不会。下面我们对编号小于SIGRTMIN的信号进行讨论。 1) SIGHUP本信号在用户终端连接(正常或非正常)结束时发出, 通常是在终端的控制进程结束时, 通知同一session内的各个作业, 这时它们与控制终端不再关联。登录Linux时,系统会分配给登录用户一个终端(Session)。在这个终端运行的所有程序,包括前台进程组和后台进程组,一般都属于这个
     Session。当用户退出Linux登录时,前台进程组和后台有对终端输出的进程将会收到SIGHUP信号。这个信号的默认操作为终止进程,因此前台进 程组和后台有终端输出的进程就会中止。不过可以捕获这个信号,比如wget能捕获SIGHUP信号,并忽略它,这样就算退出了Linux登录,wget也 能继续下载。此外,对于与终端脱离关系的守护进程,这个信号用于通知它重新读取配置文件。 2) SIGINT程序终止(interrupt)信号, 在用户键入INTR字符(通常是Ctrl-C)时发出,用于通知前台进程组终止进程。
     3) SIGQUIT和SIGINT类似, 但由QUIT字符(通常是Ctrl-/)来控制. 进程在因收到SIGQUIT退出时会产生core文件, 在这个意义上类似于一个程序错误信号。 4) SIGILL执行了非法指令. 通常是因为可执行文件本身出现错误, 或者试图执行数据段. 堆栈溢出时也有可能产生这个信号。 5) SIGTRAP由断点指令或其它trap指令产生. 由debugger使用。 6) SIGABRT调用abort函数生成的信号。 7) SIGBUS非法地址, 包括内存地址对齐(alignment)出错。比如访问一个四个字长的整数,
     但其地址不是4的倍数。它与SIGSEGV的区别在于后者是由于对合法存储地址的非法访问触发的(如访问不属于自己存储空间或只读存储空间)。 8) SIGFPE在发生致命的算术运算错误时发出. 不仅包括浮点运算错误, 还包括溢出及除数为0等其它所有的算术的错误。 9) SIGKILL用来立即结束程序的运行. 本信号不能被阻塞、处理和忽略。如果管理员发现某个进程终止不了,可尝试发送这个信号。 10) SIGUSR1留给用户使用 11) SIGSEGV试图访问未分配给自己的内存, 或试图往没有写权限的内存地址写数据.
     12) SIGUSR2留给用户使用 13) SIGPIPE管道破裂。这个信号通常在进程间通信产生,比如采用FIFO(管道)通信的两个进程,读管道没打开或者意外终止就往管道写,写进程会收到SIGPIPE信号。此外用Socket通信的两个进程,写进程在写Socket的时候,读进程已经终止。 14) SIGALRM时钟定时信号, 计算的是实际的时间或时钟时间. alarm函数使用该信号. 15) SIGTERM程序结束(terminate)信号, 与SIGKILL不同的是该信号可以被阻塞和处理。通常用来要求程序自己正常退出,shell命令kill缺省产生这个信号。如果进程终止不了,我们才会尝试SIGKILL。
     17) SIGCHLD子进程结束时, 父进程会收到这个信号。如果父进程没有处理这个信号,也没有等待(wait)子进程,子进程虽然终止,但是还会在内核进程表中占有表项,这时的子进程称为僵尸进程。这种情 况我们应该避免(父进程或者忽略SIGCHILD信号,或者捕捉它,或者wait它派生的子进程,或者父进程先终止,这时子进程的终止自动由init进程来接管)。 18) SIGCONT让一个停止(stopped)的进程继续执行. 本信号不能被阻塞. 可以用一个handler来让程序在由stopped状态变为继续执行时完成特定的工作.
     例如, 重新显示提示符... 19) SIGSTOP停止(stopped)进程的执行. 注意它和terminate以及interrupt的区别:该进程还未结束, 只是暂停执行. 本信号不能被阻塞, 处理或忽略. 20) SIGTSTP停止进程的运行, 但该信号可以被处理和忽略. 用户键入SUSP字符时(通常是Ctrl-Z)发出这个信号 21) SIGTTIN当后台作业要从用户终端读数据时, 该作业中的所有进程会收到SIGTTIN信号. 缺省时这些进程会停止执行. 22) SIGTTOU类似于SIGTTIN,
     但在写终端(或修改终端模式)时收到. 23) SIGURG有"紧急"数据或out-of-band数据到达socket时产生. 24) SIGXCPU超过CPU时间资源限制. 这个限制可以由getrlimit/setrlimit来读取/改变。 25) SIGXFSZ当进程企图扩大文件以至于超过文件大小资源限制。 26) SIGVTALRM虚拟时钟信号. 类似于SIGALRM, 但是计算的是该进程占用的CPU时间. 27) SIGPROF类似于SIGALRM/SIGVTALRM, 但包括该进程用的CPU时间以及系统调用的时间.
     28) SIGWINCH窗口大小改变时发出. 29) SIGIO文件描述符准备就绪, 可以开始进行输入/输出操作. 30) SIGPWRPower failure 31) SIGSYS非法的系统调用。 在以上列出的信号中,程序不可捕获、阻塞或忽略的信号有:SIGKILL,SIGSTOP不能恢复至默认动作的信号有:SIGILL,SIGTRAP默认会导致进程流产的信号有:SIGABRT,SIGBUS,SIGFPE,SIGILL,SIGIOT,SIGQUIT,SIGSEGV,SIGTRAP,SIGXCPU,SIGXFSZ默认会导致进程退出的信号有:SIGALRM,SIGHUP,SIGINT,SIGKILL,SIGPIPE,SIGPOLL,SIGPROF,SIGSYS,SIGTERM,SIGUSR1,SIGUSR2,SIGVTALRM默认会导致进程停止的信号有:SIGSTOP,SIGTSTP,SIGTTIN,SIGTTOU默认进程忽略的信号有:SIGCHLD,SIGPWR,SIGURG,SIGWINCH此外,SIGIO在SVR4是退出,在4.3BSD中是忽略;SIGCONT在进程挂起时是继续,否则是忽略,不能被阻塞本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/skywalker_nick/archive/2009/01/12/3758962.aspx
    
    展开全文
  • Linux信号类型

    千次阅读 2020-11-07 19:59:00
    Linux信号类型 1、信号种类 root@yjc:~/apue/signal# kill -l 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2 13) ...

    Linux信号类型

    1、信号种类
    root@yjc:~/apue/signal# kill -l
     1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL       5) SIGTRAP
     6) SIGABRT      7) SIGBUS       8) SIGFPE       9) SIGKILL     10) SIGUSR1
    11) SIGSEGV     12) SIGUSR2     13) SIGPIPE     14) SIGALRM     15) SIGTERM
    16) SIGSTKFLT   17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP
    21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU     25) SIGXFSZ
    26) SIGVTALRM   27) SIGPROF     28) SIGWINCH    29) SIGIO       30) SIGPWR
    31) SIGSYS      34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3
    38) SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
    43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
    48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
    53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7
    58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
    63) SIGRTMAX-1  64) SIGRTMAX
    

    总计64个信号类型,在/usr/include/x86_64-linux-gnu/bits/signum-generic.h中有对其进行解释。

    root@yjc:/usr/include/x86_64-linux-gnu/bits# cat signum-generic.h 
    /* Signal number constants.  Generic template.
       Copyright (C) 1991-2018 Free Software Foundation, Inc.
       This file is part of the GNU C Library.
    
       The GNU C Library is free software; you can redistribute it and/or
       modify it under the terms of the GNU Lesser General Public
       License as published by the Free Software Foundation; either
       version 2.1 of the License, or (at your option) any later version.
    
       The GNU C Library is distributed in the hope that it will be useful,
       but WITHOUT ANY WARRANTY; without even the implied warranty of
       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       Lesser General Public License for more details.
    
       You should have received a copy of the GNU Lesser General Public
       License along with the GNU C Library; if not, see
       <http://www.gnu.org/licenses/>.  */
    
    #ifndef _BITS_SIGNUM_GENERIC_H
    #define _BITS_SIGNUM_GENERIC_H 1
    
    #ifndef _SIGNAL_H
    #error "Never include <bits/signum-generic.h> directly; use <signal.h> instead."
    #endif
    
    /* Fake signal functions.  */
    
    #define SIG_ERR  ((__sighandler_t) -1)  /* Error return.  */
    #define SIG_DFL  ((__sighandler_t)  0)  /* Default action.  */
    #define SIG_IGN  ((__sighandler_t)  1)  /* Ignore signal.  */
    
    #ifdef __USE_XOPEN
    # define SIG_HOLD ((__sighandler_t) 2)  /* Add signal to hold mask.  */
    #endif
    
    /* We define here all the signal names listed in POSIX (1003.1-2008);
       as of 1003.1-2013, no additional signals have been added by POSIX.
       We also define here signal names that historically exist in every
       real-world POSIX variant (e.g. SIGWINCH).
    
       Signals in the 1-15 range are defined with their historical numbers.
       For other signals, we use the BSD numbers.
       There are two unallocated signal numbers in the 1-31 range: 7 and 29.
       Signal number 0 is reserved for use as kill(pid, 0), to test whether
       a process exists without sending it a signal.  */
    
    /* ISO C99 signals.  */
    #define SIGINT          2       /* Interactive attention signal.  */
    #define SIGILL          4       /* Illegal instruction.  */
    #define SIGABRT         6       /* Abnormal termination.  */
    #define SIGFPE          8       /* Erroneous arithmetic operation.  */
    #define SIGSEGV         11      /* Invalid access to storage.  */
    #define SIGTERM         15      /* Termination request.  */
    
    /* Historical signals specified by POSIX. */
    #define SIGHUP          1       /* Hangup.  */
    #define SIGQUIT         3       /* Quit.  */
    #define SIGTRAP         5       /* Trace/breakpoint trap.  */
    #define SIGKILL         9       /* Killed.  */
    #define SIGBUS          10      /* Bus error.  */
    #define SIGSYS          12      /* Bad system call.  */
    #define SIGPIPE         13      /* Broken pipe.  */
    #define SIGALRM         14      /* Alarm clock.  */
    
    /* New(er) POSIX signals (1003.1-2008, 1003.1-2013).  */
    #define SIGURG          16      /* Urgent data is available at a socket.  */
    #define SIGSTOP         17      /* Stop, unblockable.  */
    #define SIGTSTP         18      /* Keyboard stop.  */
    #define SIGCONT         19      /* Continue.  */
    #define SIGCHLD         20      /* Child terminated or stopped.  */
    #define SIGTTIN         21      /* Background read from control terminal.  */
    #define SIGTTOU         22      /* Background write to control terminal.  */
    #define SIGPOLL         23      /* Pollable event occurred (System V).  */
    #define SIGXCPU         24      /* CPU time limit exceeded.  */
    #define SIGXFSZ         25      /* File size limit exceeded.  */
    #define SIGVTALRM       26      /* Virtual timer expired.  */
    #define SIGPROF         27      /* Profiling timer expired.  */
    #define SIGUSR1         30      /* User-defined signal 1.  */
    #define SIGUSR2         31      /* User-defined signal 2.  */
    
    /* Nonstandard signals found in all modern POSIX systems
       (including both BSD and Linux).  */
    #define SIGWINCH        28      /* Window size change (4.3 BSD, Sun).  */
    
    /* Archaic names for compatibility.  */
    #define SIGIO           SIGPOLL /* I/O now possible (4.2 BSD).  */
    #define SIGIOT          SIGABRT /* IOT instruction, abort() on a PDP-11.  */
    #define SIGCLD          SIGCHLD /* Old System V name */
    
    /* Not all systems support real-time signals.  bits/signum.h indicates
       that they are supported by overriding __SIGRTMAX to a value greater
       than __SIGRTMIN.  These constants give the kernel-level hard limits,
       but some real-time signals may be used internally by glibc.  Do not
       use these constants in application code; use SIGRTMIN and SIGRTMAX
       (defined in signal.h) instead.  */
    #define __SIGRTMIN      32
    #define __SIGRTMAX      __SIGRTMIN
    
    /* Biggest signal number + 1 (including real-time signals).  */
    #define _NSIG           (__SIGRTMAX + 1)
    
    #endif /* bits/signum-generic.h.  */
    

    #define SIG_ERR ((__sighandler_t) -1) /* Error return. /
    #define SIG_DFL ((__sighandler_t) 0) /
    Default action. /
    #define SIG_IGN ((__sighandler_t) 1) /
    Ignore signal. */

    当信号发生时,我们可以用信号处理函数捕捉该信号,当信号处理函数

           = SIG_ERR,表示返回错误
           
           = SIG_IGN,表示我们忽略该信号,系统中大多数信号都是使用该处理方式进行处理的,但是,SIGKILL,SIGSTOP信号不能被忽略。
    
           = SIG_DFL,表示执行系统默认动作。
    
        定义我们自己的信号处理函数,捕捉信号。
    
    /* Signals.  */
    #define SIGHUP          1       /* Hangup (POSIX).  终端连接断开信号*/
    #define SIGINT          2       /* Interrupt (ANSI).  中断信号,终端中输入ctrl+c,可中断前台进程*/
    #define SIGQUIT         3       /* Quit (POSIX).   退出信号,终端中输入ctrl+\,可退出前台进程,同时产生core文件*/
    #define SIGILL          4       /* Illegal instruction (ANSI). 非法指令信号,4.3BSD的abort函数产生该信号 */
    #define SIGTRAP         5       /* Trace trap (POSIX).  调试信号,当在程序中设置断点后,该信号使得调试程序获得控制权*/
    #define SIGABRT         6       /* Abort (ANSI). 程序异常终止信号,abort函数产生该信号 */
    #define SIGIOT          6       /* IOT trap (4.2 BSD).  功能同SIGABRT*/
    #define SIGBUS          7       /* BUS error (4.2 BSD).  程序访问不存在的内存区域时,产生该信号*/
    #define SIGFPE          8       /* Floating-point exception (ANSI).  算术异常,如除以0*/
    #define SIGKILL         9       /* Kill, unblockable (POSIX).  不能被忽略,非阻塞,可杀死任意一个运行中的进程*/
    #define SIGUSR1         10      /* User-defined signal 1 (POSIX).  用户自定义1*/
    #define SIGSEGV         11      /* Segmentation violation (ANSI). 当程序访问没有访问权限的内存区域,或者访问非可读的内存区域时,产生该信号,如数组越界 */
    #define SIGUSR2         12      /* User-defined signal 2 (POSIX). 用户自定义2 */
    #define SIGPIPE         13      /* Broken pipe (POSIX). 当管道读端已关闭,继续往管道中写,产生该信号 */
    #define SIGALRM         14      /* Alarm clock (POSIX). alarm函数超时时产生该信号,默认动作是程序终止 */
    #define SIGTERM         15      /* Termination (ANSI).  终止程序信号,命令kill默认使用该参数*/
    #define SIGSTKFLT       16      /* Stack fault.  */
    #define SIGCLD          SIGCHLD /* Same as SIGCHLD (System V).  */
    #define SIGCHLD         17      /* Child status has changed (POSIX).  子进程终止或停止时,产生该信号,默认被忽略*/
    #define SIGCONT         18      /* Continue (POSIX).  */
    #define SIGSTOP         19      /* Stop, unblockable (POSIX).  停止一个作业控制进程*/
    #define SIGTSTP         20      /* Keyboard stop (POSIX).  ctrl+z产生该信号,改信号使得前台进程挂起*/
    #define SIGTTIN         21      /* Background read from tty (POSIX).  */
    #define SIGTTOU         22      /* Background write to tty (POSIX).  */
    #define SIGURG          23      /* Urgent condition on socket (4.2 BSD).  */
    #define SIGXCPU         24      /* CPU limit exceeded (4.2 BSD).  进程超过了CPU软限制产生该信号*/
    #define SIGXFSZ         25      /* File size limit exceeded (4.2 BSD).  进程超过了文件大小软限制产生该信号*/
    #define SIGVTALRM       26      /* Virtual alarm clock (4.2 BSD).  */
    #define SIGPROF         27      /* Profiling alarm clock (4.2 BSD).  */
    #define SIGWINCH        28      /* Window size change (4.3 BSD, Sun).  */
    #define SIGPOLL         SIGIO   /* Pollable event occurred (System V).  */
    #define SIGIO           29      /* I/O now possible (4.2 BSD).  */
    #define SIGPWR          30      /* Power failure restart (System V).  */
    #define SIGSYS          31      /* Bad system call.  */
    #define SIGUNUSED       31
    
    #define _NSIG           65      /* Biggest signal number + 1
                                       (including real-time signals).  */
    
    #define SIGRTMIN        (__libc_current_sigrtmin ())
    #define SIGRTMAX        (__libc_current_sigrtmax ())
    
    展开全文
  • 【Linux系统编程】Linux信号列表

    千次阅读 2019-11-08 18:36:40
    Linux信号编号02. 信号简介03. 特殊信号04. 附录 01. Linux信号编号 在 Linux 下,每个信号的名字都以字符 SIG 开头,每个信号和一个数字编码相对应,在头文件 signum.h 中,这些信号都被定义为正整数。信号名定义...
  • Linux信号

    千次阅读 2018-04-10 20:38:50
    在上一篇文章中,我们已经介绍...Linux信号概念https://blog.csdn.net/aaronlanni/article/details/79794665 一、阻塞信号 1、信号与其相关概念 实际执行信号的处理动作称为信号递达(Delivery) 信号从产生到递达之间
  • Linux信号量详解

    万次阅读 2018-05-02 13:29:02
    Linux信号量详解1.什么是信号量信号量是一种特殊的变量,访问具有原子性。只允许对它进行两个操作:1)等待信号量当信号量值为0时,程序等待;当信号量值大于0时,信号量减1,程序继续运行。2)发送信号量将信号量值加...
  • Linux信号机制

    千次阅读 2016-04-21 23:43:29
    Linux信号机制Linux信号机制 一管理层次及结构 1 数据结构 11 中断向量表的模拟 12 中断请求寄存器的模拟 二 信号的安装 1 概述 2 代码分析 3 其它函数 三信号发送 1 kill函数和sigqueue 2 代码分析 四响应信号 一、...
  • Linux信号概述

    2016-02-28 20:54:56
    Linux信号概述  信号是由用户、系统或者进程发送给目标进程的信息,以通知目标进程某个状态的改变或系统异常。发送信号  Linux下,一个进程给其他进程发送信号的API是kill函数。其定义如下:#include int kill...
  • Linux 信号机制

    千次阅读 2013-09-04 07:43:10
    Linux信号是一种“软中断”处理机制,它提供了一种处理异步事件的方法;信号也可用于进程间通信(一个进程可以向另一个进程发送信号)。   信号的分类 1、 按可靠性:分为可靠信号及不可靠信号 不可靠信号是指信号...
  • Linux信号通讯编程

    2015-12-27 14:24:57
    Linux信号通讯编程
  • Linux信号列表

    2015-07-21 16:22:39
    在命令行终端中输入命令: kill -l 结果如下图所示: 参考资料 [1]Linux信号列表
  • Linux信号(signal) 机制
  • 「信号机制」简述Linux信号

    千次阅读 2018-05-20 20:10:54
    工作中再次接触到了Linux信号,以前认为由于离底层比较远,信号没什么用,但这次发现其的一个用途,故打算在此做个简单记录。 信号是操作系统和程序间通信的一种方式,程序监听信号,并在收到信号后按照既定指示进行...
  • linux信号处理

    千次阅读 2011-09-13 14:34:04
    Linux信号集 1.信号集概念 信号集是一个能表示多个信号的数据类型,sigset_t set ;set即一个信号集。既然是一个集合,就需要对集合进行添加/删除等操作。 int sigemptyset(sigset_t *set); 将set集合置空 int ...
  • linux信号机制

    千次阅读 2009-12-04 23:59:00
    linux信号机制 信号提供了一种通知进程系统事件发生的机制,它也是作为用户进程之间通信和同步的一种原始机制。在进程迁移的情况下,如何处理信号呢?这部分介绍了MOSIX系统对信号机制的处理。LINUX信号机制信号是...
  • Linux信号和信号处理

    千次阅读 2011-07-20 11:46:45
    Linux信号列表 名称 默认动作 说明 SIGHUP 终止进程 终端线路挂断 SIGINT 终止进程 中断进程 SIGQUIT 建立CORE文件 终止进程,并且生成core文件 SIGILL 建立CORE文件 非法指令 SI
  • Linux信号机制学习笔记:::: 我的疑问: 1.在Linux内核中信号机制的底层实现是什么??? 2.信号的作用是什么???其设计之初的目的是什么??? 是为了解决什么问题而存在??? 3.为什么...
  • Linux 信号列表

    万次阅读 2015-05-26 17:40:43
    Linux 下,每个信号的名字都以字符 SIG 开头,每个信号和一个数字编码相对应,在头文件 signum.h 中,这些信号都被定义为正整数。信号名定义路径:/usr/include/i386-linux-gnu/bits/signum.h 列表中,编号为 1 ~...
  • Linux信号处理机制原理

    千次阅读 2016-01-06 21:42:03
    在之前的文章信号入门详解中,我们已经了解了信号的基础知识,下来给大家介绍Linux信号处理机制的实现原理 一、信号机制 在Linux中,信号是进程间通讯的一种方式,它采用的是异步机制。当信号发送...
  • Linux信号实践(2) --信号分类

    千次阅读 2015-02-18 15:31:17
    信号分类 不可靠信号Linux信号机制基本上是从UNIX系统中继承过来的。早期UNIX系统中的信号机制比较简单和原始,后来在实践中暴露出一些问题,它的主要问题是: 1.进程每次处理信号后,就将对信号的响应设置为默认...
  • Linux 信号理解(二)

    千次阅读 2015-08-05 20:20:41
    linux信号基本概念见,Linux 信号理解(一)
  • Linux信号系统详解

    千次阅读 2012-11-18 22:25:29
    [Linux信号系统简介]  在Linux系统中,信号机制是在软件层次上对中断机制的一种模拟。一个进程接收到信号之后,有相应的信号的处理程序,而一个进程也可以给另外一个(或一组)进程发送信号。在内核版本的0.11...
  • Linux信号

    千次阅读 2021-02-15 22:08:52
    查看信号量 [root@localhost ~]# kill -l 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) ...
  • linux信号量使用

    千次阅读 2019-03-06 15:12:20
    Linux进程间通信方式–信号,管道,消息队列,信号量,共享内存 Posix 信号量与System v信号量的区别 信号量-内核信号量、POSIX信号量、system V信号Linux线程的信号量同步 linux进程间通信-信号量(semaphore) ...
  • linux信号处理机制

    2012-06-09 15:04:39
    本文简单介绍下Linux信号处理机制: 首先,先说一下什么是信号。信号本质上是在软件层次上对中断机制的一种模拟,其主要有以下几种来源: 程序错误:除零,非法内存访问… 外部信号:终端Ctrl-C产生SGINT信号,...
  • 3、执行缺省操作,linux对每种信号都有默认的操作。 信号的发送通过kill函数和raise函数,两者的区别在于raise函数可以向本进程发送信号。   下面的代码展示了如何使用两个函数: 在实例中首先...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 31,506
精华内容 12,602
关键字:

linux信号

linux 订阅