Linux进程通信---信号

概念

每个信号都有一个数字编码。中断信号通常是编码2。

信号处理函数有点像捕鼠器。一个信号意味着什么具有破坏性的事情发射,并被捕获。

信号(signal)是一种进程间通信机制,它给应用程序提供一种异步的软件中断,使应用程序有机会接受其他程序活终端发送的命令(即信号)。应用程序收到信号后,有三种处理方式:忽略,默认,或捕捉。进程收到一个信号后,会检查对该信号的处理机制。如果是SIG_IGN,就忽略该信号;如果是SIG_DFT,则会采用系统默认的处理动作,通常是终止进程或忽略该信号;如果给该信号指定了一个处理函数(捕捉),则会中断当前进程正在执行的任务,转而去执行该信号的处理函数,返回后再继续执行被中断的任务。

为信号安装处理函数 signal
这里写图片描述

捕捉信号

#include <stdio.h>
#include <signal.h>
#include <unistd.h>

void f(int signum)
{
    printf("OUCH!\n");
}

int main()
{
    // 为终断信号SIGINT安装处理函数f
    signal(SIGINT, f);

    for(int i=0; i<5; ++i)
    {
        printf("hello\n");
        sleep(1);
    }
    return 0;
}

这里写图片描述
程序有2个独立的控制流,每次按下Ctr+C,内核都会调用函数f来处理SIGINT信号。

处理多个信号 sigaction

一个进程可能被各种来源的信号中断。信号可能以任何顺序到达。signa提供了一种简单但不完整的信号处理机制。POSIX接口,即sigaction提供了复杂的、明确定义的方法来控制进程如何对各种信号组合做出反应。
这里写图片描述

定制信号处理函数 struct sigaction

struct sigaction
{
    // 老的信号处理方式(SIG_DFL、SIG_INT或处理函数)
    void (*sa_handler)(); 

    // 新的信号处理方式
    // 不但可以得到信号编号,还可以获悉被调用的原因以及产生问题的上下文的相关信息
    void (*sa_sigaction)(int, siginfo_t *, void *);  

    // 指定哪些信号要被阻塞。阻塞信号时防止数据毁损的重要技术。
    sigset_t sa_mask;

    // 部分:
    // SA_SIGINFO:使用sa_sigaction的处理函数,否则使用sa_handler的处理函数
    // SA_RESETHAND:当调用信号处理函数时,将信号的处理函数重置为缺省值SIG_DFL
    // SA_NODEFER:在处理信号时关闭信号自动阻塞。这样就允许递归调用信号处理函数
    // SA_RESTART:如果信号中断了进程的某个系统调用,则系统自动启动该系统调用
    int sa_flags;
}

使用sigaction
在处理SIGINT时阻塞SIGQUIT

扫描二维码关注公众号,回复: 1039702 查看本文章
#include <stdio.h>
#include <signal.h>
#include <unistd.h>

void inthandler(int s)
{
    printf("\nCalled with signal %d\n", s);
    sleep(s);
    printf("\ndone handling signal %d\n", s);
}

int main()
{
    struct sigaction newhandler;
    newhandler.sa_handler = inthandler;  // 信号处理函数
    newhandler.sa_flags = SA_RESETHAND | SA_RESTART; 

    sigset_t blocked;
    sigemptyset(&blocked);  // 清空所有位
    sigaddset(&blocked, SIGQUIT);  // 将SIGQUIT加入阻塞列表
    newhandler.sa_mask = blocked;  // 设置阻塞信号集

    if(sigaction(SIGINT, &newhandler, NULL) == -1)
        perror("sigaction");
    else
    {
        char x[BUFSIZ];
        while(1)
        {
            fgets(x, BUFSIZ, stdin);
            printf("input: %s", x);
        }
    }
}

这里写图片描述
以很快速度连续按Ctrl+C和Ctr+\,退出信号将被阻塞直到中断信号处理完毕。

这里写图片描述
连续按下Ctr+C,进程被第二个信号杀死。如果像捕获所有Ctr+C,将SA_RESTHAND掩码从sa_flags中去掉。

参考
https://blog.csdn.net/dragon101788/article/details/10438855
https://baike.baidu.com/item/sigaction/4515754?fr=aladdin
Unix/Linux编程实践教程 Bruce Molay

猜你喜欢

转载自blog.csdn.net/u012319493/article/details/79778932