• Linux学习4-信号


     

        信号

       信号是Unix和Linux系统响应某些条件而产生的一个条件。接收到该信号的进程会相应的采取一些行动。

       信号是由于某些错误条件而生成的,如内存冲突,浮点处理器错误或非法指令等。它们由shell和终端处理器生成来引起中断,他们还可以作为在进程间传递消息的或修改行为的一种方式,

            明确地由一个进程发送给另一个进程。无论何种情况,它们的的编程接口都是相同的。信号可以被生成、捕获、响应或忽略。

           信号的名称是在头文件signed.h定义的。它们以SIG开头。

            在键盘上敲入中断字符(Ctrl+C 组合键)就会向前台进程(即现在在运行的的程序)发送SIGINT(终端中断)信号,这将引起该程序的终止,除非它事先安排捕获这个信号。

       命令行实现:

        如果想发送一个信号给进程,而该进程不是当前的前台进程,就需要使用kill命令。

            例如 要向运行在另一个终端的PID为512的进程发送“挂断”信号,可以使用如下命令:

            kill  -HUP 512

        ps:SIGHUP   连接挂断

           信号有关程序:

           1.捕获信号

           程序可以使用signal库函数来处理信号,

           #include <signal.h>

           void (*signal(ing sig, void (*func)(int)))(int);

           两个参数:

       sig :准备捕获或忽略的信号量

          func:收到指定的信号量后要调用的函数。可以使用两个特殊值之一来代替信号量处理函数。

          SIG_IGN  忽略信号

          SIG_DFL 恢复默认行为

          下面的示例程序将完成以下功能:当第一次敲下Ctrl+C时做出约定的反应,第二次敲下Ctrl+C时退出。

          

    #include<stdio.h>
    #include<signal.h>
    void deal(int sig)
    {
        printf("i get a sinal is %d",sig);
        (void)signal(SIGINT, SIG_DFL);
    }
    int main()
    {
        (void)signal(SIGINT,deal);
        while(1)
        {
         printf("hello world!
    ");
         sleep(1);
        }
    
    }

      运行效果:

            

      分析:当用户第一次输入Ctrl+C时,函数deal会被调用,输出一条信息,然后把信号SIGINT的处理方式恢复为默认状态。第二次输入Ctrl+C的时候就会终止程序运行。

          main函数的作用是截获Ctrl+C组合键产生的SIGINT函数。没有信号出现时,它会在一个无限循环中每隔一秒打印一条消息。

      2.发送信号

      进程可以通过调用kill函数向包括它本身在内的其它进程发送一个信号。如果程序没有发送该信号的权限,对kill函数的调用功能就将失败。

        失败的常见原因是目标进程由另外一个用户所拥有。这个函数和同名的shell命令完成同样的功能,定义如下:

         #include <sys/types.h>

       #include <signal.h>

         int kill (pid_t, int sig)

         kill函数把参数sig给定的信号量发送给由参数pid_t给出的进程号所指定的进程,成功时返回0。kill调用会在失败时返回-1并设置errno变量。失败的原因可能是:

      给定的信号无效(errno设置为EINVAL),发送进程权限不够(errno设置为EPERM),目标进程不存在(errno设置为ESRCH)。

         要想发送一个信号,发送进程必须拥有相应的权限。这通常意味着两个进程必须拥有相同的用户ID(即你只能发送信号给属于自己的进程,但超级用户可以发送信号给任何进程)。

         示例代码如下:

    #include<sys/types.h>
    #include<signal.h>
    #include<stdio.h>
    #include<unistd.h>
    #include<stdlib.h>
    
    static int alarm_stat = 0;
    
    void ding (int sig)
    {
        printf("the sig is %d
    ",sig);
        alarm_stat = 1;
    }
    int main()
    {
        pid_t pid;   
        printf("the alarm program starting!
    ");
       
        pid=fork();
        switch(pid)
        {
            case -1:
              perror("fork failed");
              exit(1);
            case 0:
              sleep(5);     
              kill(getppid(),SIGALRM);
              exit(2);
        } 
        
        printf("this is parent!
    ");
        (void)signal(SIGALRM,ding);
        pause();
        if(alarm_stat)
        {
            printf("Ding!!!!
    ");
        }  
        printf("Done!
    ");
        exit(0);
    }

      执行效果:

              

      程序分析如下:

          新函数 pause() 作用 把程序的执行挂起知道有一个信号出现为止。当程序接收到一个信号时,预设好的信号处理函数将开始运行,程序也恢复正常的执行。

          该函数通过fork调动启动新的进程。这个子进程休眠5S后向它的父进程发送一个SIGALRM信号。父进程在安排好捕获SIGALRM信号后暂停运行,直道接收到一个信号为止,通过在信号处理函数中

      设置标志,然后在main函数中检查标志来完成消息的输出。

        

      程序中使用信号将带来一个特殊的问题:“如果信号出现在系统调用的执行过程中会发生什么情况?” 答案是 视情况而定。

         在编写程序中处理信号的部分的代码时候必须非常小心,因为在使用信号的程序中会出现各种各用的“竞态条件”,例如如果

         调用pause函数来等待一个信号,可信号却出现在调用pause之前,就会使程序无限期的等待一个不会发生的事件。

    以上内容来自《Linux程序设计第四版》

  • 相关阅读:
    forward和redirect的区别详解
    j2ee部分jar包的作用
    Struts2的工作原理(图解)详解
    struts2的s:iterator 标签 详解
    Struts2 控制标签:<s:if>、<s:elseif>和<s:else>
    Struts2 资源配置文件国际化详解
    ActionContext和ServletActionContext区别以及action访问servlet API的三种方法
    js获取class
    怎么解决eclipse报PermGen space异常的问题
    SQL模糊查找语句详解
  • 原文地址:https://www.cnblogs.com/xiaodeyao/p/6443207.html
Copyright © 2020-2023  润新知