zoukankan      html  css  js  c++  java
  • linux进程间通信--信号通信

    信号

    信号是异步进程间通信方式

    进程对信号的响应方式:
    <1>忽略
    SIGKILL 和 SIGSTOP 不能忽略

    <2>捕捉
    当进程收到信号,此时执行的信号处理函数

    <3>默认

    SIGSTOP 改信号用于暂停一个进程,且不能被阻塞,忽略,和处理,默认操作为暂停进程
    大部分信号对进程的默认操作方式都是杀死进程
    子进程状态发生改变的时候,操作系统向父进程发送SIGCHLD,默认对它处理方式是忽略

    信号的发送与设置

    1.信号发送 kill()与raise()

    int kill(pid_t pid, int sig);
     

    参数: 
    pid:可能选择有以下四种

    1. pid大于零时,发送信号给进程号为pid的进程。
    2. pid等于零时,信号将送往所有与调用kill()的那个进程属同一个使用组的进程。
    3. pid等于-1时,信号发送给所有的进程表中的进程,除了进程1(init)。
    4. pid小于-1时,信号将送往以-pid为组标识的进程。

    sig:准备发送的信号代码,假如其值为零则没有任何信号送出,但是系统会执行错误检查,通常会利用sig值为零来检验某个进程是否仍在执行。


    返回值说明: 成功执行时,返回0。失败返回-1

    errno被设为以下的某个值:

    EINVAL:指定的信号码无效(参数 sig 不合法)

    EPERM:权限不够无法传送信号给指定进程

    ESRCH:参数 pid 所指定的进程或进程组不存在

    int raise(int signo);

    注意:raise函数只允许进程向自身发送信号

    实例如下:

    #include <stdio.h>
    #include <stdlib.h>
    #include <signal.h>
    #include <sys/types.h>
    #include <sys/wait.h>
    int main(int argc, const char *argv[])
    {

      pid_t pid;
      int ret;

    if((pid=fork())<0)
    {
      printf("Fork error ");
      exit(EXIT_FAILURE);
    }
    if(pid==0)
    {
      printf("child(pid:%d) is waiting for any signal ",getpid());
      raise(SIGSTOP);//在子进程中使用raise()函数发出SIGSTOP信号,使子进程暂停
      exit(EXIT_SUCCESS);
    }
    else
    {
      if(waitpid(pid,NULL,WNOHANG)==0)
      {
        sleep(10);
        kill(pid,SIGKILL);
        printf("parent kill child process %d ",pid);
      }
    }
    waitpid(pid,NULL,0);
    return 0;
    }

     编译并运行 ./a.out

    并查看

    ps  aux|grep a.out

    可以看到结果如下:

    此时子进程处于暂停状态 

    10s后运行结果如下:

     

    typedef void (*sighandler_t)(int);
    sighandler_t signal(int signum, sighandler_t handler);
    功能:设置进程对信号处理方式
    参数:
    @signum 信号的编号
    @handler
    SIG_IGN : 忽略信号
    SIG_DFL : 使用默认处理方式
    函数名 : 捕捉方式处理

    返回值:
    成功返回handler,失败返回SIG_ERR

     实例如下:

    void handler_child(int signum){
      printf("receive signal ");
      waitpid(-1,NULL,WNOHANG);
    }

    int main(int argc, const char *argv[])
    {
      pid_t pid;

      if(signal(SIGCHLD,handler_child) == SIG_ERR){
      perror("Fail to signal");
      exit(EXIT_FAILURE);
    }

    pid = fork();
    if(pid < 0){
        perror("Fail to fork");
        exit(EXIT_FAILURE);
      }

    if(pid == 0){
      while(1)
      ;
    }

    if(pid > 0){
      while(1){
        printf("Hello word1 ");
        sleep(1);
      }
    }
    return 0;
    }

    功能:
      进行不阻塞,不轮训方式回收僵尸态子进程

    编译运行然后查看 ps aux |grep a.out

    可以看到子进程正在运行在

    然后发送信号

     kill -SIGHUP 18881

    再查看结果如下 ps aux |grep a.out

    可以看到子进程已经退出,因为如果收到SIGHUP信号并没有处理,默认处理为终止进程,而父进程收到SIGCHLD的信号,进行收尸处理!

    运行结果

    sigaction函数
    sigaction函数的功能是用于改变进程接收到特定信号后的行为。
    int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
    参数
     第一个参数是信号的值,可以为除了SIGKILL及SIGSTOP外的任何一个特定有效的信号(因为这两个信号定义了自己的处理函数,将导致信号安装错误)
     第二个参数是指向节后sigaction的一个实例的指针,在sigaction的实例中,指定了对特定信号的处理,可以为NULL,进程会以缺省方式对信号处理
     第三个参数oldact指向的对象用来保存原来对相应信号的处理,可以为NULL
    返回值:函数成功返回0,失败返回-1。
    sigaction函数检查或修改与指定信号相关联的处理动作,该函数取代了signal函数。
    因为signal函数在信号未决时接收信号可能出现问题,所以使用sigaction更安全。
    sigaction结构体
    struct sigaction {
        void     (*sa_handler)(int);//信号处理程序 不接受额外数据
        void     (*sa_sigaction)(int, siginfo_t *, void *);//信号处理程序,能接受额外数据,可以和sigqueue配合使用
        sigset_t   sa_mask;
        int        sa_flags;//影响信号的行为SA_SIGINFO表示能接受数据
        void     (*sa_restorer)(void);//废弃
    };
    第二个参数最为重要,其中包含了对指定信号的处理、信号所传递的信息、信号处理函数执行过程应屏蔽掉哪些函数等等。
    回调函数sa_handler、sa_sigaction只能任选其一

    简单一点的用法:
       struct sigaction action;

      sigaction(SIGINT,0,&action);

      action.sa_handler=my_func;//绑定信号处理函数

      sigaction(SIGINT,&action,0);

    但更常用的方法是和sigqueue搭配
    2.在进程中设置一个定时器

    unsigned int alarm(unsigned int seconds);
    参数:
    @seconds 定时的时间,以秒为单位

    注意:
    一旦定时时间完成,操作系统就会向进程发送SIGALRM信号

    int pause(void);

      pause函数用于将调用进程挂起直到接收到信号为止

    实例如下:

    #include <unistd.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <signal.h>
    void test(int sig)
    {
      printf("receive siganl :%d ",sig);
    }
    int main()
    {
      signal(SIGALRM,test);
      alarm(3);
      pause();
      printf("I free! ");
    }

    运行结果为

    但是如果将信号处理函数去掉呢?

    int main()
    {
      alarm(3);
      pause();
      printf("I free! ");
    }

    其中 I free还会打印吗?

  • 相关阅读:
    用友U8 | 【基础设置】添加财务项目分类
    用友U8 | 【出纳管理】通过收支操作出纳收款生单,生成收款单表头信息带不过去
    MySQL经典45题(一)
    用友U8 | 【出纳管理】出纳模块银行日记账提示"已经加过类型为MD的锁"
    用友U8 | 【凭证打印】如何将凭证输出为PDF电子格式
    用友U8 | 【请购单列表】后台数据库导请购单列表
    用友U8 | 【数据权限档案分配】导出客户档案分配表
    用友U8 | 【出纳管理】收支操作,客户收款,出纳收款查询不了相关数据
    鼠标事件中鼠标的坐标是如何定义的
    Visual Studio 中各种文件后缀名是什么意思
  • 原文地址:https://www.cnblogs.com/bwbfight/p/9291676.html
Copyright © 2011-2022 走看看