精华内容
下载资源
问答
  • Linux下信号详解及捕捉信号

    千次阅读 2018-08-07 11:23:34
    信号的基本概念 每个信号都有一个编号和一个宏定义名称 ,这些宏定义可以在 signal.h 中找到。 使用kill -l命令查看系统中定义的信号列表: 1-31是普通信号 regular signal(非可靠信号); 34-64是实时信号 real...

    信号的基本概念

    每个信号都有一个编号和一个宏定义名称 ,这些宏定义可以在 signal.h 中找到。

    使用kill -l命令查看系统中定义的信号列表: 1-31是普通信号 regular signal(非可靠信号); 34-64是实时信号 real time signal(可靠信号)

    所有的信号都由操作系统来发!

    对信号的三种处理方式

    1、忽略此信号:大多数信号都可使用这种方式进行处理,但有两种信号却决不能被忽略。它们是:SIGKILLSIGSTOP。这两种信号不能被忽略的,原因是:它们向超级用户提供一种使进程终止或停止的可靠方法。另外,如果忽略某些由硬件异常产生的信号(例如非法存储访问或除以0),则进程的行为是示定义的。

    2、直接执行进程对于该信号的默认动作 :对大多数信号的系统默认动作是终止该进程。

    3、捕捉信号:执行自定义动作(使用signal函数),为了做到这一点要通知内核在某种信号发生时,调用一个用户函数handler。在用户函数中,可执行用户希望对这种事件进行的处理。注意,不能捕捉SIGKILLSIGSTOP信号。

    ?

    1

    2

    3

    #include <signal.h>

    typedef void( *sighandler_t)(int);

    sighandler_t signal(int signum, sighandler_t handler);

    signal函数的作用:给某一个进程的某一个特定信号(标号为signum)注册一个相应的处理函数,即对该信号的默认处理动作进行修改,修改为handler函数所指向的方式。

    1、第一个参数是信号的标号

    2、第二个参数,sighandler_t是一个typedef来的,原型是void (*)(int)函数指针,int的参数会被设置成signum

    举个代码例子:

    ?

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    #include<stdio.h>

    #include<signal.h>

    void handler(int sig)

    {

     printf("get a sig,num is %d\n",sig);

    }

      

    int main()

    {

     signal(2,handler);

     while(1)

     {

      sleep(1);

      printf("hello\n");

     }

     return 0;

    }

      修改了2号信号(Ctrl-c)的默认处理动作为handler函数的内容,则当该程序在前台运行时,键入Ctrl-c后不会执行它的默认处理动作(终止该进程)

    信号的处理过程:

    进程收到一个信号后不会被立即处理,而是在恰当 时机进行处理!什么是适当的时候呢?比如说中断返回的时候,或者内核态返回用户态的时候(这个情况出现的比较多)。

    信号不一定会被立即处理,操作系统不会为了处理一个信号而把当前正在运行的进程挂起(切换进程),挂起(进程切换)的话消耗太大了,如果不是紧急信号,是不会立即处理的。操作系统多选择在内核态切换回用户态的时候处理信号,这样就利用两者的切换来处理了(不用单独进行进程切换以免浪费时间)。

    总归是不能避免的,因为很有可能在睡眠的进程就接收到信号,操作系统肯定不愿意切换当前正在运行的进程,于是就得把信号储存在进程唯一的PCB(task_struct)当中。

    产生信号的条件

    1.用户在终端按下某些键时,终端驱动程序会发送信号给前台程序。

         例如:Ctrl-c产生SIGINT信号,Ctrl-\产生SIGQUIT信号,Ctrl-z产生SIGTSTP信号

    2.硬件异常产生信号。

         这类信号由硬件检测到并通知内核,然后内核向当前进程发送适当的信号。

         例如:当前进程执行除以0的指令,CPU的运算单元会产生异常,内核将这个进程解释为SIGFPE信号发送给当前进程。
                   当前进程访问了非法内存地址,MMU会产生异常,内核将这个异常解释为SIGSEGV信号发送给进程。

    3.一个进程调用kill(2)函数可以发送信号给另一个进程。

         可以用kill(1)命令发送信号给某个进程,kill(1)命令也是调用kill(2)函数实现的,如果不明确指定信号则发送SIGTERM信号,该信号的默认处理动作是终止进程。

    信号的产生

    1.通过终端按键产生信号

    举个栗子:写一个死循环,前台运行这个程序,然后在终端键入Ctrl-c

      当CPU正在执行这个进程的代码 , 终端驱动程序发送了一 个 SIGINT 信号给该进程,记录在该进程的 PCB中,则该进程的用户空间代码暂停执行 ,CPU从用户态 切换到内核态处理硬件中断。

      从内核态回到用户态之前, 会先处理 PCB中记录的信号 ,发现有一个 SIGINT 信号待处理, 而这个信号的默认处理动作是终止进程,所以直接终止进程而不再返回它的用户空间代码执行。

     2.调用系统函数向进程发信号

    ?

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    /*************************************************************************

     > File Name: test.c

     > Author:Lynn-Zhang

     > Mail: iynu17@yeah.net

     > Created Time: Fri 15 Jul 2016 03:03:57 PM CST

     ************************************************************************/

      

    #include<stdio.h>

    int main()

    {

     printf("get pid :%d circle ...\n",getpid());

     while(1);

     return 0;

    }

    写一个上面的程序在后台执行死循环,并获取该进程的id,然后用kill命令给它发送SIGSEGV信号,可以使进程终止。也可以使用kill -11 5796,11是信号SIGSEGV的编号。

    打开终端1,运行程序:

    利用终端2,给进程发送信号

     终端1 显示进程被core了:

    kill命令是调用kill函数实现的。kill函数可以给一个指定的进程发送指定信号

    raise函数可 以给当前进程发送指定的信号 (自己给自己发信号 )

    ?

    1

    2

    3

    #include<signal.h>

    int kill(pid_t pid,int signo);

    int raise(int signo);

    这两个函数都是成功返回0,错误返回-1.

    除此之外,abort函数使当前进程接收到SIGABRT信号而异常终止。

    ?

    1

    2

    #include<stdlib.h>

    void abort(void);

    就像 exit函数一样 ,abort 函数总是会成功的 ,所以没有返回值。

    3.由软件条件产生信号

    ?

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    /*************************************************************************

     > File Name: alarm.c

     > Author:Lynn-Zhang

     > Mail: iynu17@yeah.net

     > Created Time: Fri 15 Jul 2016 08:52:02 PM CST

     ************************************************************************/

      

    #include<stdio.h>

      

    int main()

    {

     int count=0;

     alarm(1);

     while(1)

     {

     printf("%d\n",count);

     count++;

     }

     return 0;

    }

     通过实现以上代码,调用alarm函数可以设定一个闹钟,告诉内核在seconds秒之后给当前进程发SIGALRM信号, 该信号的默认处理动作是终止当前进程。

       该程序会在1秒钟之内不停地数数,并打印计数器,1秒钟到了就被SIGALRM信号终止。由于电脑配置等的不同,每台电脑一秒钟之内计数值是不同的一般是不同的。

    ?

    1

    2

    #include <unistd.h>

    unsigned int alarm(unsigned int seconds);

      alarm函数的返回值是0或上次设置闹钟剩余的时间。

    阻塞信号

     1.信号在内核中的表示:

    信号递达delivery:实际执行信号处理信号的动作

    信号未决pending:信号从产生到抵达之间的状态,信号产生了但是未处理

    忽略:抵达之后的一种 动作

    阻塞block:收到信号不立即处理     被阻塞的信号将保持未决状态,直到进程解除对此信号的阻塞,才执行抵达动作

    信号产生和阻塞没有直接关系 抵达和解除阻塞没有直接关系!

    进程收到一个信号后,不会立即处理,它会在恰当的时机被处理。

    每个信号都由两个标志位分别表示阻塞和未决,以及一个函数指针表示信号的处理动作。

    在上图的例子中,

      1. SIGHUP信号未阻塞也未产生过,当它递达时执行默认处理动作。

      2. SIGINT信号产生过,但正在被阻塞,所以暂时不能递达。虽然它的处理动作是忽略,但在没 有解除阻塞之前不能忽略这个信号,因为进程仍有机会改变处理动作之后再解除阻塞。

      3. SIGQUIT信号未产生过,一旦产生SIGQUIT信号将被阻塞,它的处理动作是用户自定义函数sighandler。阻塞信号集也叫作信号屏蔽字。

    信号产生但是不立即处理,前提条件是要把它保存在pending表中,表明信号已经产生。

    2.信号集操作函数

    ?

    1

    2

    3

    4

    5

    6

    #include <signal.h>

    int sigemptyset(sigset_t *set); //初始化set所指向的信号集,使所有信号的对应位清0

    int sigfillset(sigset_t *set); //初始化set所指向的信号集,表示该信号集的有效信号包括系统支持的所有信号

    int sigaddset(sigset_t *set, int signo); //在该信号集中添加有效信号

    int sigdelset(sigset_t *set, int signo); //在该信号集中删除有效信号

    int sigismember(const sigset_t *set, int signo); //用于判断一个信号集的有效信号中是否包含某种信号

    参数解析:

    sigset_t结构体的参数表示信号集,信号操作的时候都是以信号集合的方式进行操作,需要事先创建一个该结构体的对象,然后把想要操作的信号添加到信号集合对象当中去

    signo就是信号的标号了

    3.调用函数sigprocmask可以读取或更改进程的信号屏蔽字(阻塞信号集)。

    ?

    1

    2

    #include <signal.h>

    int sigprocmask(int how, const sigset_t *set, sigset_t *oset);

       一个进程的信号屏蔽字规定了当前阻塞而不能递送给该进程的信号集。调用函数sigprocmask可以检测或更改(或两者)进程的信号屏蔽字。如果调用sigprocmask解除了对当前若干个未决信号的阻塞,则在sigprocmask返回前,至少将其中 一个信号递达。

    参数解析:

     how,有三个宏

         SIG_BLOCK      添加到block表当中去

         SIG_UNBLOCK  从block表中删除

         SIG_SETMASK  设置block表 设置当前信号屏蔽字为set所指向的值

     set表示新设置的信号屏蔽字,oset表示当前信号屏蔽字

    处理方式:

          set 非空, oset 为NULL :按照how指示的方法更改set指向信号集的信号屏蔽字。

          set 为NULL,oset 非空:读取oset指向信号集的信号屏蔽字,通过oset参数传出。

          set 和 oset 都非空 :现将原来的信号屏蔽字备份到oset里,然后根据sethow参数更改信号屏蔽字。

    4. sigpending读取当前进程的未决信号集,通过set参数传出

    ?

    1

    2

    #include <signal.h>

    int sigpending(sigset_t *set);

    这是一个输出型参数,会把当前进程的pending表打印到传入的set集中。

    实例验证上面几个函数:

     

    一开始没有任何信号,所以pending表中全是0,我通过Ctrl+C传入2号信号,看到pending表中有2号被置位了,经过10秒取消阻塞,2号信号被处理(经过我自定义的函数)

    Linux下捕捉信号

    信号由三种处理方式:

         忽略

         执行该信号的默认处理动作

         捕捉信号

    如果信号的处理动作是用户自定义函数,在信号递达时就调用这个自定义函数,这称为捕捉信号

    进程收到一个信号后不会被立即处理,而是在恰当时机进行处理!即内核态返回用户态之前 !

    但是由于信号处理函数的代码在用户空间,所以这增加了内核处理信号捕捉的复杂度。

    内核实现信号捕捉的步骤:

          1、用户为某信号注册一个信号处理函数sighandler

          2、当前正在执行主程序,这时候因为中断、异常或系统调用进入内核态。

          3、在处理完异常要返回用户态的主程序之前,检查到有信号未处理,并发现该信号需要按照用户自定义的函数来处理。

          4、内核决定返回用户态执行sighandler函数,而不是恢复main函数的上下文继续执行!(sighandlermain函数使用的是不同的堆栈空间,它们之间不存在调用和被调用的关系,是两个独立的控制流程)

          5、sighandler函数返回后,执行特殊的系统调用sigreturn从用户态回到内核态

          6、检查是否还有其它信号需要递达,如果没有 则返回用户态并恢复主程序的上下文信息继续执行。

    signal

    给某一个进程的某一个信号(标号为signum)注册一个相应的处理函数,即对该信号的默认处理动作进行修改,修改为handler函数指向的方式;

    ?

    1

    2

    3

    #include <signal.h>

    typedef void (*sighandler_t)(int);

    sighandler_t signal(int signum, sighandler_t handler);<br>//即:<br>void (*signal(int, void(*)(int)))(int);

    signal函数接受两个参数:一个整型的信号编号,以及一个指向用户定义的信号处理函数的指针。  

    此外,signal函数的返回值是一个指向调用用户定义信号处理函数的指针。

    sigaction

    sigaction函数可以读取和修改与指定信号相关联的处理动作。

    ?

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    #include <signal.h>

    int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

    struct sigaction

    {

      void (*sa_handler)(int);  //信号处理方式

      void (*sa_sigaction)(int, siginfo_t *, void *); //实时信号的处理方式 暂不讨论

      sigset_t sa_mask; //额外屏蔽的信号

      int sa_flags;

      void (*sa_restorer)(void);

    };

    signum是指定信号的编号。

    处理方式:

         1、若act指针非空,则根据act结构体中的信号处理函数来修改该信号的处理动作。

         2、若oact指针非 空,则通过oact传出该信号原来的处理动作。

         3、现将原来的处理动作备份到oact里,然后根据act修改该信号的处理动作。

    (注:后两个参数都是输入输出型参数!)

    将sa_handler三种可选方式:

         1、赋值为常数SIG_IGN传给sigaction表示忽略信号;

         2、赋值为常数SIG_DFL表示执行系统默认动作;

         3、赋值为一个函数指针表示用自定义函数捕捉信号,或者说向内核注册一个信号处理函 数,该函数返回值为void,可以带一个int参数,通过参数可以得知当前信号的编号,这样就可以用同一个函数处理多种信号。

    (注:这是一个回调函数,不是被main函数调用,而是被系统所调用)

      当某个信号的处理函数被调用时,内核自动将当前信号加入进程的信号屏蔽字,当信号处理函数返回时自动恢复原来的信号屏蔽字,这样就保证了在处理某个信号时,如果这种信号再次产生,那么 它会被阻塞到当前处理结束为止。

     pause

    pause函数使调用进程挂起直到有信号递达!

    ?

    1

    2

    #include <unistd.h>

    int pause(void);

    处理方式: 

         如果信号的处理动作是终止进程,则进程终止,pause函数没有机会返回;

         如果信号的处理动作是忽略,则进程继续处于挂起状态,pause不返回;

         如果信号的处理动作是捕捉,则调用了信号处理函数之后pause返回-1,errno设置为EINTR。

         所以pause只有出错的返回值(类似exec函数家族)。错误码EINTR表示“被信号中断”。

     举个栗子

         1、定义一个闹钟,约定times秒后,内核向该进程发送一个SIGALRM信号;

         2、调用pause函数将进程挂起,内核切换到别的进程运行;

         3、times秒后,内核向该进程发送SIGALRM信号,发现其处理动作是一个自定义函数,于是切回用户态执行该自定义处理函数;

         4、进入sig_alrm函数时SIGALRM信号被自动屏蔽,从sig_alrm函数返回时SIGALRM信号自动解除屏蔽。然后自动执行特殊的系统调用sigreturn再次进入内核,之后再返回用户态继续执行进程的主控制流程(main函数调用的mytest函数)。

         5、pause函数返回-1,然后调用alarm(0)取消闹钟,调用sigaction恢复SIGALRM信号以前的处理 动作。

    ?

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    40

    41

    42

    43

    44

    /*************************************************************************

     > File Name: Pause.c

     > Author:Lynn-Zhang

     > Mail: iynu17@yeah.net

     > Created Time: Sun 14 Aug 2016 12:27:03 PM CST

     ************************************************************************/

      

    #include<stdio.h>

    #include<signal.h>

    #include<unistd.h>

    void sig_alarm(int signum)

    {

     printf("I am a custom handler!\n");

    }

    void mysleep(unsigned int times)

    {

     //注册两个信号处理动作

     struct sigaction new,old;

     new.sa_handler=sig_alarm; //信号处理函数

     sigemptyset(&new.sa_mask);//不屏蔽任何信号屏蔽字

     new.sa_flags=0;

      

     //对SIGALRM 信号的默认处理动作修改为自定义处理动作

     sigaction(SIGALRM,&new,&old);

     alarm(times);

     pause(); //挂起等待

     alarm(1);

     sleep(2);

     alarm(0); //取消闹钟

     //恢复SIGALRM 信号到默认处理动作

     sigaction(SIGALRM,&old,NULL);

     alarm(1);

     sleep(2);

    }

    int main()

    {

     while(1)

     {

     mysleep(2);

     printf("many seconds passed\n");

     printf("###################\n");

     }

     return 0;

    }

       

    定义一个闹钟并挂起等待,收到信号后执行自定义处理动作,在没有恢复默认处理动作前,收到SIGALRM信号都会按照其自定义处理函数来处理。恢复自定义处理动作之后收到SIGALRM信号则执行其默认处理动作即终止进程!

    总结

    展开全文
  • Linux信号详解

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

    Linux信号量详解

    1.什么是信号量
    信号量是一种特殊的变量,访问具有原子性。
    只允许对它进行两个操作:
    1)等待信号量
    当信号量值为0时,程序等待;当信号量值大于0时,信号量减1,程序继续运行。
    2)发送信号量
    将信号量值加1。

    我们使用信号量,来解决进程或线程间共享资源引发的同步问题。

    2.Linux中信号量的使用
    Linux提供了一组信号量API,声明在头文件sys/sem.h中。
    1)semget函数:新建信号量

    int semget(key_t key,int num_sems,int sem_flags);

    key:信号量键值,可以理解为信号量的唯一性标记。
    num_sems:信号量的数目,一般为1
    sem_flags:有两个值,IPC_CREATE和IPC_EXCL,
    IPC_CREATE表示若信号量已存在,返回该信号量标识符。
    IPC_EXCL表示若信号量已存在,返回错误。

    返回值:相应的信号量标识符,失败返回-1

    2)semop函数:修改信号量的值

    int semop(int sem_id,struct sembuf *sem_opa,size_t num_sem_ops);

    sem_id:信号量标识符
    sem_opa:结构如下

    复制代码
    struct sembuf{  
        short sem_num;//除非使用一组信号量,否则它为0  
        short sem_op;//信号量在一次操作中需要改变的数据,通常是两个数,一个是-1,即P(等待)操作,  
                        //一个是+1,即V(发送信号)操作。  
        short sem_flg;//通常为SEM_UNDO,使操作系统跟踪信号,  
                        //并在进程没有释放该信号量而终止时,操作系统释放信号量  
    }; 
    复制代码

    3)semctl函数:用于信号量的初始化和删除

    int semctl(int sem_id,int sem_num,int command,[union semun sem_union]);

    command:有两个值SETVAL,IPC_RMID,分别表示初始化和删除信号量。
    sem_union:可选参数,结构如下:

    union semun{  
        int val; 
        struct semid_ds *buf;  
        unsigned short *arry;  
    }; 

    一般用到的是val,表示要传给信号量的初始值。

    3.Linux信号量使用示例
    下例中,我们写了一个程序,程序中有一个char类型的字符,char message='x'
    然后同时运行这个程序的两个实例。
    第一个实例,带一个参数,将参数的第一个字符赋给message,比如为'0'
    第二个实例,使用默认message值'x'
    我们的目的是,使用信号量,循环执行这两个实例,
    我们可以看到执行结果应该是'x0x0x0x0x0x0'

    复制代码
    #include<stdio.h>
    #include<stdlib.h>
    #include<sys/sem.h>
    union semun
    {
        int val;
        struct semid_ds *buf;
        unsigned short *array;
    };
    int sem_id;
    int set_semvalue()
    {
        union semun sem_union;    
        sem_union.val = 1;
        if(semctl(sem_id,0,SETVAL,sem_union)==-1)
            return 0;
        return 1;
    }
    int semaphore_p()
    {
        struct sembuf sem_b;
        sem_b.sem_num = 0;
        sem_b.sem_op = -1;
        sem_b.sem_flg = SEM_UNDO;
        if(semop(sem_id,&sem_b,1)==-1)
        {
            fprintf(stderr,"semaphore_p failed\n");
            return 0;
        }
        return 1;
    }
    int semaphore_v()
    {
        struct sembuf sem_b;
        sem_b.sem_num = 0;
        sem_b.sem_op = 1;
        sem_b.sem_flg = SEM_UNDO;
        if(semop(sem_id,&sem_b,1)==-1)
        {
            fprintf(stderr,"semaphore_v failed\n");
            return 0;
        }
        return 1;
    }
    void del_semvalue()
    {
        //删除信号量
        union semun sem_union;
        if(semctl(sem_id,0,IPC_RMID,sem_union)==-1)
            fprintf(stderr,"Failed to delete semaphore\n");
    }
    int main(int argc,char *argv[])
    {
        char message = 'x';
        //创建信号量
         sem_id = semget((key_t)1234,1,0666|IPC_CREAT);
        if(argc>1)
        {
            //初始化信号量
            if(!set_semvalue())
            {
                fprintf(stderr,"init failed\n");
                exit(EXIT_FAILURE);
            }
            //参数的第一个字符赋给message
            message = argv[1][0];
        }
        int i=0;
        for(i=0;i<5;i++)
        {
            //等待信号量
            if(!semaphore_p())
                exit(EXIT_FAILURE);
            printf("%c",message);
            fflush(stdout);
            sleep(1);
            //发送信号量
            if(!semaphore_v())
                exit(EXIT_FAILURE);
            sleep(1);
        }
        printf("\n%d-finished\n",getpid());
        if(argc>1)
        {
            //退出前删除信号量
            del_semvalue();
        }
        exit(EXIT_SUCCESS);
    }
    复制代码

    输出结果:

    展开全文
  • linux信号详解

    千次阅读 2018-05-09 18:16:05
    本文讲述了信号的基本概念,信号列表的详细介绍,如何用系统调用操作信号,以及常用信号示例。

    信号概念

    定义:

     信号是事件发生时对进程的通知机制。

    信号产生场景:

    • 键盘事件
    • 非法内存操作
    • 硬件故障
    • 从用户态切换到内核态

    信号分类:

    • 标准信号
      标准信号的局限性:

      1. 阻塞信号可能会丢失。当一个信号阻塞时,这个信号即使多次发送给进程,也被执行一次信号句柄。

      2. 信号交付没有携带与信号有关信息。接受到信号的进程无法区分同种信号的不同情况,也不知道信号从何而来。

      3. 信号的交付没有优先级。当有多个信号悬挂与一个进程时,交付的顺序不确定。

    • 实时信号
      实时信号对标准信号做了一下扩充,有以下的特点:

      1. 增加了信号从SIGRTMIN到SIGRTMAX的实时信号,可以通过sysconf(_SC_RTSIG_MAX)获得当前操作系统支持的实时信号的个数。

      2. 实时信号在队列中并按顺序交付。同一类型的实时信号将按顺序交付给进程。

      3. 实时信号可以携带额外的信息。

      4. 进程能够通过专门的函数更快的回复信号。

      5. 当定时器到期、空消息队列有消息到达、有异步IO完成时,信号能够及时交付给进程。

    进程收到信号的三种处理方式:

    1.默认处理:

    • 忽略信号:内核将信号丢弃,信号没有对进程产生任何影响
    • 终止进程:进程异常终止
    • 产生核心转储文件,同时终止文件
    • 停止进程:暂停进程的执行
    • 恢复之前暂停的进程继续执行

    2.忽略处理:

    • 信号来了不做任何处理不能忽略SIGKILL和SIGSTOP

    3.捕获并处理:

    • 信号来了捕获信号,并执行程序员自己写的程序不能捕获SIGKILL和SIGSTOP

    信号列表:

    这里写图片描述
    列表中,编号为1 ~ 31的信号为传统UNIX支持的信号,是不可靠信号(非实时的),编号为32 ~ 63的信号是后来扩充的,称做可靠信号(实时信号)。不可靠信号和可靠信号的区别在于前者不支持排队,可能会造成信号丢失,而后者不会。

    系统信号详解:

    1. SIGHUP
       当终端断开时,将发送该信号给终端控制进程。SIGHUP信号还可用于守护进程。
    2. SIGINT
       当用户键入终端中断字符(如:Ctrl + C)终端驱动程序将发送该信号给前台进程组。该信号默认行为是终止进程。
    3. SIGQUIT
       当用户在键盘键入退出字符(如Ctrl+\)时,该信号将发往前台进程组。默认情况下,该信号终止进程,并生成可用于调试的核心转储文件。当进程陷入无限循环或者不在响应,使用该信号很合适。
    4. SIGILL
       进程试图非法执行机器语言指令,系统将向该进程发送该信号。
    5. SIGTRAP
       该信号用来实现断点调试功能以及strace命令所执行的跟踪系统调用功能。
    6. SIGABRT
       当进程调用abort函数时,系统向该进程发送该信号。默认情况下,该信号会终止进程,并产生核心转储文件。
    7. SIGBUS
       总线错误,表示发生了某种内存访问错误。当使用mmap()所创建的内存映射时,如果试图访问的地址超出了底层内存映射文件的结尾,会产生该错误。
    8. SIGFPE
       在发生致命的算术运算错误时发出. 不仅包括浮点运算错误, 还包括溢出及除数为0等其它所有的算术的错误。
    9. SIGKILL
       此信号为必杀信号,处理器程序无法阻塞、忽略或者捕获,故而总能杀死进程(僵尸进程除外)。
    10. SIGUSR1
       用户自定义信号,内核绝不会为进程产生该信号。
    11. SIGSEGV
       试图访问未分配给自己的内存, 或试图往没有写权限的内存地址写数据.
    12. SIGUSR2
       同SIGUSR1描述。
    13. SIGPIPE
       当某一进程试图向管道,FIFO或套接字写入信息时,如果这些设备并无相应的阅读进程,系统将产生该信号。(管道破裂)
    14. SIGALRM
       经调用alarm()或setitimer()而设置的实时定时器一旦到期,内核将产生该信号。
    15. SIGTERM
       这是用来终止进程的标准信号,也是kill和killall命令所发送的默认信号。用户经常会使用kil -9显示向进程发送SIGKILL信号,然而这一做法通常是错误的。精心设计的应用程序应当为SIGTERM信号设置处理器程序,以便于其能够预先清理临时文件和释放资源,做到全身而退。发送SIGKILL信号可以杀掉某个进程,从而绕开了SIGTERM的信号处理程序。因此,总是应该首先尝试使用SIGTERM信号来终止进程,而把SIGKILL信号作为最后手段,去对付那些失控的进程。
    16. SIGSTKFLT
       linux对该信号做了定义,但并未加以使用。
    17. SIGCHLD
       当父进程的某一子进程退出时,内核将向父进程发送该信号。
    18. SIGCONT
       该信号发送给已停止的进程,进程将恢复运行。当接收信号的进程当前处于非停止状态 时,默认情况下将忽略该信号。
    19. SIFSTOP
       进程收到该信号将停止运行,处理器程序无法将其阻塞、忽略或者捕获,故而总能停止进程。
    20. SIGTSTP
       作业控制的停止信号,当用户在键盘输入挂起字符(如:Ctrl+Z)时,将发送该信号给前台进程组,使其停止运行。(该信号可以被处理和忽略)
    21. SIGTTIN
       在作业控制shell下运行时,若后台进程组试图对终端进行read()操作,终端驱动程序则将该进程组发送该信号。该信号默认将停止进程。
    22. SIGTTOU
       该信号与SIGTTIN类似,但在写终端(或修改终端模式)时收到。
    23. SIGURG
       系统发送该信号给一个进程,表示套接字上存在带外(紧急)数据。
    24. SIGXCPU
       当进程的CPU时间超出对应的资源限制时,将发送此信号给进程。
    25. SIGXFSZ
       如果进程试图增大文件而突破对进程文件大小的资源限制时,将发送该信号给进程。
    26. SIGVTALRM
       虚拟时钟信号. 类似于SIGALRM, 但是计算的是该进程占用的CPU时间。
    27. SIGPROF
       类似于SIGALRM/SIGVTALRM, 但包括该进程用的CPU时间以及系统调用的时间.
    28. SIGWINCH
       窗口大小改变时发出该信号。
    29. SIGIO
       文件描述符准备就绪, 可以开始进行输入/输出操作。
    30. SIGPWR
       电源故障信号。
    31. SIGSYS
       如果进程发起的系统调用有误,将产生该信号。

    操作信号

    使用命令发送信号给进程

    kill -信号 进程id
    kill命令是使用kill函数实现的。

    #include <sys/types.h>
    #include <signal.h>
    
           int kill(pid_t pid, int sig);

    pid:指定哪个进程

    • pid>0:会发送信号给指定进程号为pid的进程。
    • pid=0:发送信号给调用进程组同组的每个进程,包括调用进程本身。
    • pid=-1:调用进程有权将信号发往的每一个进程,除去init(1号进程)和调用进程自身。如果特权级进程发起这一调用,那么会将信号发给系统中所有进程。有时也称这种信号称为广播信号。
    • pid<-1:会向该pid绝对值的进程组下属进程发送信号。
      sig:发送哪个信号

    kill还有一个特殊的用途:当sig=0时,表示无信号发送,调用kill()函数会去执行错误检查,查看是否可以向目标进程发送信号。这也就意味着可以指定空信号来检测ID进程是否存在。

    给本进程发信号:

     #include <signal.h>
           int raise(int sig);

    调改变信号处置:

    系统调用函数

     #include <signal.h>
    
           typedef void (*sighandler_t)(int);
    
           sighandler_t signal(int signum, sighandler_t handler);
    参数:
    signum:表示希望修改的信号编号
    handler:表示信号到达时执行的处理器程序的地址,该函数无返回值。
      1. 自定义函数
      2.SIG_DFL:将信号处置重置为默认值。这适用于将之前signal()调用所改变的信号处置还原。
      3.SIG_IGN:忽略该信号。

    handler一般格式:

    void handler(int sig)
    {
        //处理程序
    }
    返回值:
    成功:signal()的返回值是之前的信号处置,像handler参数一样,是一个指针,指向的是带有一个整形参数且无返回值的函数。
    失败:返回SIG_ERR

    信号处理器程序介绍

     信号处理器程序时当指定信号传递给进程时将会调用的一个函数。
    调用信号处理程序,可能会随时打断主程序流程,内核代表进程来调用处理器程序,当处理器程序返回时,主程序会在打断的位置处恢复执行。
    这里写图片描述
    信号处理器程序设计原则:力求简单。

    示例代码:

    void handler(int sig) //处理器程序
    {
        printf("ctrl + c\n");
    }
    
    int main()
    {
        int sig = SIGINT; //信号
        if(signal(sig,handler) == SIG_ERR)
            perror("signal"),exit(1);
    
        int i = 0;
        while(1)
        {   
            printf("%c ",i%26+'a');
            fflush(stdout);
            i++;
            sleep(1);
        }                                                                                                                                
        return 0;
    }

    执行结果:
    这里写图片描述
    当键入Ctrl+C时,会去执行信号处理程序,进程不会结束,执行完毕再返回继续执行主程序,最后发送SIGQUIT(Ctrl + \)信号,默认执行核心转储,进程退出。

    展开全文
  • linux系统下信号详解2

    千次阅读 2014-06-26 00:44:53
    信号是UNIX 系统所使用的进程通信方法中,最古老的一种。信号不但能从内核发往一个进程,也能从一个进程发往另一个进程。例如,用户在后台启动了一个要运行较长时间的程序,如果想中断其执行,可以用kill 命令把...

    信号是UNIX 系统所使用的进程通信方法中,最古老的一种。信号不但能从内核发往一个进程,也能从一个进程发往另一个进程。例如,用户在后台启动了一个要运行较长时间的程序,如果想中断其执行,可以用kill 命令把SIGTERM信号发送给这个进程,SIGTERM 将终止此进程的执行。信号还提供了向UNIX 系统进程传送软中断的简单方法。信号可以中断一个进程,而不管它正在作什么工作。由于信号的特点,所以不用它来作进程间的直接数据传送,而把它用作对非正常情况的处理。由于信号本身不能直接携带信息,这就限制了它作为一项通用的进程通信机制。

    .SIGHUP信号

         UNIX中进程组织结构为 session (会话)包含一个前台进程组及一个或多个后台进程组,一个进程组包含多个进程。一个session可能会有一个session首进程,而一个session首进程可能会有一个控制终端。一个进程组可能会有一个进程组首进程。进程组首进程的进程ID与该进程组ID相等。这儿是可能会有,在一定情况之下是没有的。与终端交互的进程是前台进程,否则便是后台进程。
    SIGHUP会在以下3种情况下被发送给相应的进程:
    1、终端关闭时,该信号被发送到session首进程以及作为job提交的进程(即用 & 符号提交的进程)
    2、session首进程退出时,该信号被发送到该session中的前台进程组中的每一个进程
    3、若父进程退出导致进程组成为孤儿进程组,且该进程组中有进程处于停止状态(收到SIGSTOP或SIGTSTP信号),该信号会被发送到该进程组中的每一个进程。
         系统对SIGHUP信号的默认处理是止收到信号的程。所以若程序中没有捕捉信号,当收到信号程就会退出。
         下面观察几种因终端关闭导致进程退出的情况,在这儿进程退出是因为收到了SIGHUP信号。login shell是session首进程。
    首先写一个测试程序,代码如下:
    #include <stdio.h>
    #include <signal.h>
    char **args;
    void exithandle(int sig)
    ...{
            printf("%s : sighup received ",args[1]);
    }
    int main(int argc,char **argv)
    ...{
            args = argv;
            signal(SIGHUP,exithandle);
            pause();
           return 0;
    }
    程序中捕捉SIGHUP信号后打印一条信息,pause()使程序暂停。
    编译后的执行文件为sigtest。
    1、命 令:sigtest front > tt.txt
       操 作:关闭终端
       结 果:tt.txt文件的内容为front : sighup received
       原 因: sigtest是前台进程,终端关闭后,根据上面提到的第1种情况,login shell作为session首进程,会收到SIGHUP信号然后退出。根据第2种情况,sigtest作为前台进程,会收到login shell发出的SIGHUP信号。
    2、命 令:sigtest back > tt.txt &
         操 作:关闭终端
          结 果:tt.txt文件的内容为 back : sighup received
          原 因: sigtest是提交的job,根据上面提到的第1种情况,sigtest会收到SIGHUP信号。
    3、命 令:写一个shell,内容为[sigtest &],然后执行该shell
          操 作:关闭终端
          结 果:ps -ef | grep sigtest 会看到该进程还在,tt文件为空
          原 因: 执行该shell时,sigtest作为job提交,然后该shell退出,致使sigtest变成了孤儿进程,不再是当前session的job了,因此sigtest即不是session首进程也不是job,不会收到SIGHUP。同时孤儿进程属于后台进程,因此login shell退出后不会发送SIGHUP给sigtest,因为它只将该信号发送给前台进程。第3条说过若进程组变成孤儿进程组的时候,若有进程处于停止状态,也会收到SIGHUP信号,但sigtest没有处于停止状态,所以不会收到SIGHUP信号。
    4、命 令:nohup sigtest > tt
          操 作:关闭终端
          结 果:tt文件为空
          原 因: nohup可以防止进程收到SIGHUP信号
    至此,我们就清楚了何种情况下终端关闭后进程会退出,何种情况下不会退出。
    要想终端关闭后进程不退出有以下几种方法,均为通过shell的方式:
    1、编写shell,内容如下
           trap "" SIGHUP #该句的作用是屏蔽SIGHUP信号,trap可以屏蔽很多信号
          sigtest
    2、nohup sigtest 可以直接在命令行执行,
           若想做完该操作后继续别的操作,可以 nohup sigtest &
    3、编写shell,内容如下
           sigtest &
           其实任何将进程变为孤儿进程的方式都可以,包括fork后父进程马上退出。
    SIGINT
    当一个用户按了中断键(一般为Ctrl+C)后,内核就向与该终端有关联的所有进程发送这种信号。它提供了中止运行程序的简便方法。
    SIGQUIT
    这种信号与SIGINT 非常相似,当用户按了退出键时(为ASCII 码FS,通常为Ctrl+\),内核就发送出这种信号。SIGQUIT 将形成POSIX 标准所描述的非正常终止。我们称这种UNIX 实现的实际操作为核心转贮(core dump),并用信息“Quit (core dump)”指出这一操作的发生。这时,该进程的映象被转贮到一个磁盘文件中,供调试之用。
    SIGILL
    当一个进程企图执行一条非法指令时,内核就发出这种信号。例如,在没有相应硬件支撑的条件下,企图执行一条浮点指令时,则会引起这种信号的发生。SIGILL 和SIGQUIT一样,也形成非正常终止。
    SIGTRAP
    这是一种由调试程序使用的专用信号。由于他的专用行和特殊性,我们不再对它作进一步的讨论。SIGTRAP 也形成非正常终止。
    SIGFPE
    当产生浮点错误时(比如溢出),内核就发出这种信号,它导致非正常终止。
    SIGKILL
    这是一个相当特殊的信号,它从一个进程发送到另一个进程,使接收到该信号的进程终止。内核偶尔也会发出这种信号。SIGKILL 的特点是,它不能被忽略和捕捉,只能通过用户定义的相应中断处理程序而处理该信号。因为其它的所有信号都能被忽略和捕捉,所以只有这种信号能绝对保证终止一个进程。
    SIGALRM
    当一个定时器到时的时候,内核就向进程发送这个信号。定时器是由改进程自己用系统调用alarm()设定的。
    SIGTERM
    这种信号是由系统提供给普通程序使用的,按照规定,它被用来终止一个进程。
    SIGSTOP
    这个信号使进程暂时中止运行,系统将控制权转回正在等待运行的下一个进程。
    SIGUSR1 和SIGUSR2
    和SIGTERM 一样,这两种信号不是内核发送的,可以用于用户所希望的任何目的。
    SIGCHLD
    子进程结束信号。UNIX 中用它来实现系统调用exit()和wait()。执行exit()时,就向子进程的父进程发送SIGCHLD 信号,如果这时父进程政在执行wait(),则它被唤醒;如果这时候父进程不是执行wait(),则此父进程不会捕捉SIGCHLD 信号,因此该信号不起作用,
    子进程进入过渡状态(如果父进程忽略SIGCHLD,子进程就结束而不会进入过渡状态)。这个机制对大多数UNIX 程序员来说是相当重要的。对于大多数情况来说,当进程接收到一个信号时,它就被正常终止,相当于进程执行了一个临时加入的exit()调用。在这种情况下,父进程能从进程返回的退出状态中了解可能发生的事情,退出状态的低8 位含有信号的号码,其高8 位为0。

    信号SIGQUIT、SIGILL、SIGTRAP、SIGSYS 和SIGFPE 会导致一个非正常终止,它们将发生核心转贮,即把进程的内存映象写入进程当前目录的core 文件之中。core 文件中以二进制的形式记录了终止时程序中全部变量之值、硬件寄存器之值和内核中的控制信息。非正常终止进程的退出状态除了其低端第7 位被置位外,其它均与通过信号正常终止时一样。
    Linux 的调试程序gdb 知道core 文件的格式,可以用它们来观察进程在转贮点上的状态。这样,就可以用gdb 正确的定出发生问题的位置。
    这里再介绍一下系统调用abort(),它在Linux 系统库stdlib.h 中定义:
    void abort(void);//实际上是abort调用raise()实现给自己发送信号;
    abort()向调用进程发送一个信号,产生一个非正常终止,即核心转贮。由于它能够使一个进程在出错时记录进程的当前状态,所以可以用它来作为调试的辅助手段。这也说明了进程可以向自己发送信号这一事实。

    UNIX 的系统调用signal()用于接收一个指定类型的信号,并可以指定相应的方法。这就是说,signal()能够将指定的处理函数与信号向关联。它在Linux 系统库signal.h 中的函数声明如下:
    int signal (int sig, __sighandler_t handler);
    Signal()有两个参数:
    第一个参数sig 指明了所要处理的信号类型,它可以取除了SIGKILL 和SIGSTOP 外的任何一种信号。参数handler 描述了与信号关联的动作,它可以取以下三种值:

                  1.一个无返回值的函数地址。

                      void func(int sig);

                  2.SIG_IGN
                      这个符号表示忽略信号。执行了相应的signal()调用好,进程会忽略类型为sig 的信号。
                  3.SIG_DFL
                      这个符号表示恢复系统对信号的默认处理。

    在父进程中设定的信号和函数的关联关系会被exec()调用自动用SIG_DFL 恢复成系统的缺省动作,这是因为在exec 的子进程中没有父进程的函数映象。

    #include <stdio.h>
    #include <stdlib.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <signal.h>
    
    void fun(int sig)
    {
    	printf("test1\n");
    }
    int main(int argc, char const *argv[])
    {
    	int fd = fork();
    	signal(SIGINT, fun);
    	if(fd < 0){
    		exit(-1);
    	}else if(fd == 0){
    		execlp("sleep","sleep","10",NULL);
    	}else{
    		sleep(10);
    	}
    	return 0;
    }
    
    


    运行结果:./a.out

                      <clt + c>

                      test1

    在Linux 中,当一个信号的信号处理函数执行时,如果进程又接收到了该信号,该信号会自动被储存而不会中断信号处理函数的执行,直到信号处理函数执行完毕再重新调用相应的处理函数。下面的程序演示了这一点:

    #include <signal.h>
    
    int interrupt()
    {
       printf(“Interrupt called\n”);
       sleep(3);
       printf(“Interrupt Func Ended.\n”);
    }
    
    main()
    {
       signal(SIGINT,interrupt);
       printf(“Interrupt set for SIGINT\n”);
       sleep(10);
       printf(“Program NORMAL ended.\n”);
       return;
    }

    执行它,结果如下:
    Interrupt set for SIGINT
    <ctrl+c>
    Interrupt called
    <ctrl+c>
    Func Ended
    Interrupt called
    Func Ended
    Program NORMAL ended.
    但是如果在信号处理函数执行时进程收到了其它类型的信号,该函数的执行就会被中断

    #include <signal.h>
    int interrupt()
    {
       printf(“Interrupt called\n”);
       sleep(3);
       printf(“Interrupt Func Ended.\n”);
    }
    int catchquit()
    {
      printf(“Quit called\n”);
       sleep(3);
       printf(“Quit ended.\n”);
    }
    main()
    {
       signal(SIGINT,interrupt);
       signal(SIGQUIT,catchquit);
       printf(“Interrupt set for SIGINT\n”);
       sleep(10);
       printf(“Program NORMAL ended.\n”);
       return;
    }

    执行这个程序的结果如下:
    Interrupt set for SIGINT
    <ctrl+c>
    Interrupt called
    <ctrl+\>
    Quit called
    Quit ended.
    Interrupt Func Ended.
    Program NORMAL ended.

    进程间发送信号
    一个进程通过对signal()的调用来处理其它进程发送来的信号。同时,一个进程也可以向其它的进程发送信号。这一操作是由系统调用kill()来完成的。kill()在linux 系统库signal.h中的函数声明如下:
           int kill(pid_t pid, int sig);
    参数pid 指定了信号发送的对象进程:它可以是某个进程的进程标识符(pid),也可以是以下的值:
    如果pid 为零,则信号被发送到当前进程所在的进程组的所有进程
    如果pid 为-1,则信号按进程标识符从高到低的顺序发送给全部的进程(这个过程受到当前进程本身权限的限制);
    如果pid 小于-1,则信号被发送给标识符为pid 绝对值的进程组里的所有进程
    需要说明的是,一个进程并不是向任何进程均能发送信号的,这里有一个限制,就是普通用户的进程只能向具有与其相同的用户标识符的进程发送信号。也就是说,一个用户的进程不能向另一个用户的进程发送信号。只有root 用户的进程能够给任何线程发送信号。
    参数sig 指定发送的信号类型。它可以是任何有效的信号。
    由于调用kill()的进程需要直到信号发往的进程的标识符,所以这种信号的发送通常只在关系密切的进程之间进行,比如父子进程之间。


    下面是一个使用kill()调用发送信号的例子。这个程序建立两个进程,并通过向对方发送信号SIGUSR1 来实现它们之间的同步。这两个进程都处于一个死循环中,在接收对方发送的信号之前,都处于暂停等待中。这是通过系统调用pause()来实现的,它能够使一个程序暂停,直至一个信号到达,然后进程输出信息,并用kill 发送一个信号给对方。当用户按了中断键,这两个进程都将终止。

    #include <signal.h>
    int ntimes=0;
    main()
    {
    int pid,ppid;
    int p_action(), c_action();
    /* 设定父进程的SIGUSR1 */
    signal(SIGUSR1,p_action);
    switch(pid=fork()) {
    case -1: /*fork 失败*/
       perror("synchro");
       exit(1);
    case 0: /*子进程模块*/
       /* 设定子进程的SIGUSR1 */
       signal(SIGUSR1,c_action);
       /* 获得父进程的标识符 */
       ppid=getppid();
       for(;;) {
          sleep(1);
          kill(ppid,SIGUSR1);
          pause();
       }
    /*死循环*/
    break;
    default: /*父进程模块*/
       for (;;) {
          pause();
          sleep(1);
          kill(pid,SIGUSR1);
       }
    /*死循环*/
    }
    }
    p_action()
    {
       printf("Patent caught signal #%d\n",++ntimes);
    }
    c_action()
    {
       printf("Child caught signal #%d\n",++ntimes);
    }

    程序运行结果如下:
    Patent caught signal #1
    Child caught signal #1
    Patent caught signal #2
    Child caught signal #2
    Patent caught signal #3
    Child caught signal #3
    Patent caught signal #4
    Child caught signal #4
    <ctrl+c>

    特别注意root用户执行时的问题,比如下面程序:

    #include <stdio.h>
    #include <stdlib.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <signal.h>
    
    int main(){
    	int fd = fork();
    	if(fd > 0){
    		exit(0);
    	}
    	while(1){
    		kill(-1,SIGINT);
    		kill(-1,SIGKILL);
    	}
    		
    	return 0;
    }
    root权限下运行,系统直接崩溃。
                                                                                                                        <span style="background-color: rgb(255, 255, 255);">         </span>
    <span style="background-color: rgb(255, 255, 255);"></span> 
    <span style="background-color: rgb(255, 255, 255);"></span> 
    <span style="font-size:18px;background-color: rgb(255, 255, 255);"><strong>系统调用alarm()和pause()                                                              1、系统调用alarm()
    alarm()是一个简单而有用的系统调用,它可以建立一个进程的报警时钟,在时钟定时器到时的时候,用信号向程序报告。alarm()系统调用在Linux 系统函数库unistd.h 中的函数声明如下:
    unsigned int alarm(unsigned int seconds);
    函数唯一的参数是seconds,其以秒为单位给出了定时器的时间。当时间到达的时候,就向系统发送一个SIGARLM信号。</strong></span>
    <span style="font-size:18px;background-color: rgb(255, 255, 255);"><strong>一个由alarm()调用设置好的报警时钟,在<span style="color:#ff0000;">通过exec()调用后,仍将继续有效</span>。但是,<span style="color:#ff0000;">它在fork()调用后中,在子进程中失效</span>。如果要使设置的报警时钟失效,只需要调用参数为零的alarm():</strong></span>
    <span style="font-size:18px;background-color: rgb(255, 255, 255);"><strong>	alarm(0)
    alarm()调用也不能积累。如果调用alarm 两次,则第二次调用就取代第一次调用。但是,alarm 的返回值柜橱了前一次设定的报警时钟的剩余时间。当需要对某项工作设置时间限制时,可以使用alarm()调用来实现。其基本方法为:先调用alarm()按时间限制值设置报警时钟,然后进程作某一工作。如果进程在规定时间以内完成这一工作,就再调用alarm(0)使报警时钟失效。如果在规定时间内未能完成这一工作,进程就会被报警时钟的SIGALRM 信号中断,然后对它进行校正。</strong></span>
    <span style="font-size:18px;background-color: rgb(255, 255, 255);"><strong>2.系统调用pause()
    系统调用pause()能使调用进程暂停执行,直至接收到某种信号为止。pause()在Linux系统函数库unistd.h 中的函数声明如下:
    	int pause(void);
    该调用没有任何的参数。它的返回始终是-1 , 此时errno 被设置为ERESTARTNOHAND。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             </strong></span>
    <span style="background-color: rgb(255, 255, 255);"></span> 
    <span style="background-color: rgb(255, 255, 255);"></span> 
    <span style="background-color: rgb(255, 255, 255);"></span> 
    <span style="background-color: rgb(255, 255, 255);"></span> 
    <span style="background-color: rgb(255, 255, 255);">                                                                                                          </span>
    展开全文
  • LINUX SIGNAL信号标志详解

    万次阅读 2011-08-16 17:36:27
    在终端使用kill -l 命令可以显示所有的信号。 $kill -l 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIG
  • LINUX SIGNAL 信号标志详解

    千次阅读 2011-07-28 14:15:48
    原文地址::...   在终端使用kill -l 命令可以显示所有的信号。 $kill -l 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKIL
  • linux c 信号详解

    千次阅读 2014-03-04 00:58:10
    信号量 当我们在多用户系统,多进程系统,或是两者混合的系统中使用线程操作编写程序时,我们经常会发现我们有段临界代码,在此处我们需要保证一个进程(或是一个线程的执行)需要排他的访问一个资源。 信号量有一...
  • Linux-信号机制详解(一)

    千次阅读 2016-07-17 00:29:05
    之前有写过SystemV的信号量机制,现在是信号。这里的信号和前面的信号量是不同的。这里的信号是进程给操作系统或进程的某种信息,让操作系统或者其他进程做出某种反应。  信号是进程间通信机制中唯一的异步通信...
  • Linux信号系统详解

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

    万次阅读 2017-10-16 16:54:22
    信号Linux编程中非常重要的部分,本文将详细介绍信号机制的基本概念、Linux信号机制的大致实现方法、如何使用信号,以及有关信号的几个系统调用。  信号机制是进程之间相互传递消息的一种方法,信号全称为软...
  • Linux信号入门详解

    千次阅读 2016-01-06 21:38:36
    一、什么是信号? 以下是维基百科对信号的定义: 在计算机科学中,信号(英语:Signals)是Unix、类Unix以及其他POSIX兼容的操作系统中进程间通讯的一种有限制的方式。它是一种异步的通知机制,用来提醒进程...
  • LinuxLinux进程信号详解

    万次阅读 2018-04-22 18:04:44
    1、当用户按这一对组合键时,这个键盘输入会产生一个硬件中断,如果CPU正在执行这个进程的代码时,则该进程的用户代码先暂停执行,用户从用户态切换到内核态处理硬件中断2、终端驱动程序将这一对组合键翻译成一个...
  • //函数指针,保存了内核对信号的处理方式 void (*sa_sigaction)(int, siginfo_t *, void *);// sigset_t sa_mask;//保存的是当进程在处理信号的时候,收到的信号 int sa_flags;//SA_SIGINFO,OS在处理信号的时候,...
  • Linux系统的信号详解

    千次阅读 2015-09-01 14:54:11
    一、信号类型  1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP  6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1  11) SIGS
  • Linux的SOCKET编程详解

    万次阅读 多人点赞 2012-04-10 17:44:52
    Linux的SOCKET编程详解 1. 网络中进程之间如何通信 进 程通信的概念最初来源于单机系统。由于每个进程都在自己的地址范围内运行,为保证两个相互通信的进 程之间既互不干扰又协调一致工作,操作系统为进程...
  • linux中的信号详解

    千次阅读 2011-09-28 20:57:43
    linux中的信号详解 原文地址: http://www.diybl.com/course/6_system/linux/Linuxjs/2008627/128768.html  Linux支持的信号列表如下。很多信号是与机器的体系结构相关的,首
  • linux信号捕捉函数详解

    千次阅读 2016-12-24 10:37:54
    信号捕捉 signal函数 注册一个信号捕捉函数: ...该函数由ANSI定义,由于历史原因在不同版本的Unix和不同版本的Linux中可能有不同的行为。因此应该尽量避免使用它,取而代之使用sigaction函数。
  • linux信号实现机制详解

    千次阅读 2016-10-27 08:20:39
    信号本质 软中断信号(signal,又简称为信号)用来通知进程发生了异步事件。在软件层次上是对中断机制的一种模拟,在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的。信号是进程间通信...
  • Linux下ps命令详解

    千次阅读 2013-11-19 14:22:53
    Linux下ps命令详解 Linux上进程有5种状态:  1. 运行(正在运行或在运行队列中等待) 2. 中断(休眠中, 受阻, 在等待某个条件的形成或接受到信号) 3. 不可中断(收到信号不唤醒和不可运行, 进程必须等待直到有...
  • 信号处理(一)在Linux下当我们想强制结束一个程序的时候,我们通常会给它发送一个信号然后该进程捕捉到信号,再然后该进程执行一定操作最终被终止.信号是UNIX和Linux系统响应某些条件而产生的一个事件,接收到该信号...
  • Linux下top命令详解

    千次阅读 2014-10-08 20:40:12
    Linux下top命令详解  top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器。top是一个动态显示过程,即可以通过用户按键来不断刷新当前状态.如果在前台执行...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 28,566
精华内容 11,426
关键字:

linux下信号7详解

linux 订阅