• Linux进程间通信-信号


    1.什么是信号
    信号是Linux系统响应某些条件而产生的一个事件,接收到该信号的进程会执行相应的操作。

    2.信号的产生
    1)由硬件产生,如从键盘输入Ctrl+C可以终止当前进程
    2)由其他进程发送,如可在shell进程下,使用命令 kill -信号标号 PID,向指定进程发送信号。
    3)异常,进程异常时会发送信号

    3.信号的处理
    信号是由操作系统来处理的,说明信号的处理在内核态。
    信号不一定会立即被处理,此时会储存在信号的信号表中。
    处理过程示意图:

    由上图中可看出信号有三种处理方式:
    1)忽略
    2)默认处理方式:操作系统设定的默认处理方式
    3)自定义信号处理方式:可自定义信号处理函数

    4.自定义信号处理方式
    1)signal函数
    原型:
    void (*signal(int sig, void (*func)(int)))(int);
    sig:信号值
    func:信号处理函数指针,参数为信号值
    代码示例如下:

    #include <signal.h>
    #include <stdio.h>
    void ouch(int sig)
    {
        printf("
    OUCH! - I got signal %d
    ", sig);
        //恢复终端中断信号SIGINT的默认行为
        (void) signal(SIGINT, SIG_DFL);
    }
    int main()
    {
        //改变终端中断信号SIGINT的默认行为,使之执行ouch函数
        //而不是终止程序的执行
        (void) signal(SIGINT, ouch);
        while(1)
        {
            printf("Hello World!
    ");
            sleep(1);
        }
        return 0;
    }

    输出结果:

    2)sigaction函数
    原型:
    int sigaction(int sig,const struct sigaction *act,struct sigaction *oact);
    sig:信号值
    act:指定信号的动作
    oact:保存原信号的动作

    sigaction结构体的定义如下:
    void (*)(int) sa_handler;处理函数指针,相当于signal函数的func参数。
    sigset_t sa_mask;处理过程中,屏蔽对sa_mask信号集的处理,sa_mask可以消除信号间的竞态。
    int sa_flags;信号处理修改器:处理函数执行完后,信号处理方式修改。如SA_RESETHAND,将信号处理方式重置为SIG_DFL
    代码示例如下:

    #include <stdio.h>
    #include <signal.h>
    void ouch(int sig)
    {
        printf("
    OUCH! - I got signal %d
    ", sig);
    }
    int main()
    {
        struct sigaction act;
        act.sa_handler = ouch;
        //创建空的信号屏蔽字,即不屏蔽任何信息
        sigemptyset(&act.sa_mask);
        //使sigaction函数重置为默认行为
        act.sa_flags = SA_RESETHAND;
        sigaction(SIGINT, &act, 0);
        while(1)
        {
            printf("Hello World!
    ");
            sleep(1);
        }
        return 0;
    }

    输出结果:

    4.信号的发送
    1)kill函数
    int kill(pid_t pid,int signo);
    pid:进程ID
    signo:信号值

    2)raise函数:只能向当前进程发信号
    int raise(int signo);
    signo:信号值

    3)abort函数:发送SIGABRT信号,可以让进程异常终止
    void abort(void);

    4)alarm函数:发送SIGALRM闹钟信号
    unsigned int alarm(unsigned int seconds);

    5.信号的阻塞
    阻塞是阻止进程收到该信号,此时信号处于未决状态,放入进程的未决信号表中,
    当解除对该信号的阻塞时,未决信号会被进程接收。

    1)阻塞信号
    原型:
    int sigprocmask(int how,const sigset_t *set,sigset_t *oset);
    how:设置block阻塞表的方式
    a.SIG_BLOCK:将信号集添加到block表中
    b.SIG_UNBLOCK:将信号集从block表中删除
    c.SIG_SETMASK:将信号集设置为block表
    set:要设置的集合
    oset:设置前保存之前block表信息

    2)获取未决信号
    前面已经讲过,阻塞的信号处于未决的状态,会放入进程的未决信号表。
    原型:
    int sigpending(sigset_t *set);
    set:out型参数,会将获得的当前进程的pending未决表中的信号集传入。

    代码示例如下:

    #include <stdio.h>
    #include <sys/signal.h>
    #include <sys/types.h>
    #include <signal.h>
    void func(int num)
    {
      printf("catch signal number is %d",num);
    }
    void printfpendingsignal(sigset_t *set)
    {
      int i;
      for(i=1;i<32;++i)
      {
        if(sigismember(set,i))
        {
          printf("1");
        }
        else
        {
          printf("0");
        }
      }
      printf("
    ");
    }
    int main()
    { 
      sigset_t s,p,o;
      signal(SIGINT,func);
      sigemptyset(&s);
      sigemptyset(&p);
      sigemptyset(&o);
      sigaddset(&s,SIGINT);
      sigprocmask(SIG_SETMASK,&s,&o);
      int count=0;
      while(1)
      {
        sigpending(&p);
        printfpendingsignal(&p);
        sleep(1);
        if(count++==10)
        {
          printf("recover!
    ");
          sigprocmask(SIG_SETMASK,&o,NULL);
        }
      }
      return 0;
    }

    输出结果:

    6.信号处理函数的安全问题
    如果信号处理过程中被中断,再次调用,然后返回到第一次调用时,要保证操作的正确性。
    这就要求信号处理函数必须是可重入的。
    可重入函数表如下:

    7.一些常见的信号

    如果进程接收到上面的这些信号,又没有安排捕获它,进程就会终止。

    其他的一些信号如下:

  • 相关阅读:
    (二分查找 拓展) leetcode 69. Sqrt(x)
    (二分查找 拓展) leetcode 162. Find Peak Element && lintcode 75. Find Peak Element
    (链表) lintcode 219. Insert Node in Sorted Linked List
    (二分查找 拓展) leetcode 34. Find First and Last Position of Element in Sorted Array && lintcode 61. Search for a Range
    (最短路 Floyd) P2910 [USACO08OPEN]寻宝之路Clear And Present Danger 洛谷
    (字符串 数组 递归 双指针) leetcode 344. Reverse String
    (二叉树 DFS 递归) leetcode 112. Path Sum
    (二叉树 DFS 递归) leetcode 101. Symmetric Tree
    (二叉树 递归) leetcode 144. Binary Tree Preorder Traversal
    (二叉树 递归 DFS) leetcode 100. Same Tree
  • 原文地址:https://www.cnblogs.com/shijingjing07/p/5672784.html
Copyright © 2020-2023  润新知