【linux高级程序设计】(第十章)Linux异步信号处理机制 2

signal安装信号

typedef void (*__sighandler_t) (int);

__sighandler_t signal (int __sig, __sighandler_t __handler) :安装信号处理函数,第1个参数是收到的信号,第2个参数是处理的函数指针,返回值也是函数指针。

三个相关的宏

  • #define SIG_ERR  ((__sighandler_t) -1)   //返回错误      (语法上是把-1强制转换为了__sighandler_t型,即函数指针型)
  • #define SIG_DFL  ((__sighandler_t) 0)    //执行信号默认操作  
  • #define SIG_IGN  ((__sighandler_t) -1)  //忽略信号

如果设置多次,最终生效的是最后一次设置操作。失败返回SIG_ERR

#include<stdio.h>
#include<unistd.h>
#include<signal.h>
void sig_usr(int sig);
int main()
{
    int i = 0;
    if(signal(SIGUSR1, sig_usr) == SIG_ERR)
        printf("Cannont catch SIGUSR1
");
    if(signal(SIGUSR2, sig_usr) == SIG_ERR)
        printf("Cannont catch SIGUSR2
");
    while(1)
    {
        printf("%2d
", i);
        pause();   //等待有信号到来
        i++;
    }
    return 0;
}

void sig_usr(int sig)
{
    if(sig == SIGUSR1)
        printf("Received SIGUSR1
");
    else if(sig == SIGUSR2)
        printf("Received SIGUSR2
");
    else
        printf("Undeclared signal %d
", sig);
}

用两个终端,一个终端执行代码,另一个终端发送信号。

发送的信号为:

处理结果为:

知识点:执行代码后面加 & 可以显示进程号

sigaction安装信号

int sigaction (int __sig, struct sigaction * __act, struct sigaction *__oact)

其中sigaction结构体的定义为:

struct sigaction{
    union{
        __sighandler_t _sa_handler;    //SIG_DFL, SIG_IGN 信号,类似signal函数
        void (*_sa_sigaction)(int, struct siginfo *, void *); //信号捕获函数,可以获取其他信息
    }__u;
    
    sigset_t sa_mask;  //执行信号捕获函数期间要屏蔽的其他信号集
    unsigned long sa_flags;  //影响信号行为的特殊标志
    void (*sa_restorer)(void);   //没有使用
};
#define sa_handler  _u._sa_handler   //对两个成员进行重定义
#define sa_sigaction _u._sa_sigaction 

屏蔽信号集sa_mask中不能屏蔽SIGKILLSIGSTOP信号。

如果,将成员sa_flags设置为SA_SIGINFO, 则通过sa_sigaction设置信号处理函数。其函数指针类型为:

void (*_sa_sigaction)(int, struct siginfo *, void *); //信号捕获函数,可以获取其他信息

第一个参数:对应信号

第三个参数:赋给指向ucontext_t类型的一个对象的指针,以引用在传递信号时被中断的接收进程或线程的上下文。

第二个参数,struct siginfo 描述信号中断的部分信息。具体结构体定义如下:

si_sigo成员包含系统生成的信号编码。

si_errno成员可能包含与实现相关的其他错误信息。如果不为0,则该成员将包含一个错误编号,用于表示导致生成该信号的条件

si_code成员包含一个标识该信号生成原因的代码

后续的联合体不同的信号将填充不同的部分。

例子:

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

void func(int signo, siginfo_t *info, void *p)
{
    printf("signo = %d
", signo);
    printf("sender pid = %d
", info->si_pid);  //打印发送者的pid
}
int main()
{
    struct sigaction act, oact;
    
    sigemptyset(&act.sa_mask);  //设置掩码为空
    act.sa_flags = SA_SIGINFO;  //需要修改sa_flags
    act.sa_sigaction = func;    //处理函数
    sigaction(SIGUSR1, &act, &oact);  //安装信号
    while(1)
    {
        printf("pid is %d Hello world.
", getpid());
        pause();    //等待一个信号
    }
}

发送信号的终端

执行代码的终端

后面有一大段关于sa_flags的说明,没仔细看。

对比sigaction的sa_handler和signal

先屏蔽信号,给自己发信号,解除屏蔽

signal

#include<stdlib.h>
#include<signal.h>
static void sig_usr1(signo)
{
    printf("SIGUSR1 function
");
}
static void sig_usr2(signo)
{
    printf("SIGUSR2 function
");
}
static void sig_alarm(signo)
{
    printf("SIGALRM function
");
}
int main(void)
{
    sigset_t newmask, oldmask;
    //安装信号处理函数
    if(signal(SIGUSR1, sig_usr1) < 0 || signal(SIGUSR2, sig_usr2) || signal(SIGALRM, sig_alarm))
        perror("signal
");
    sigemptyset(&newmask);   //掩码置空
    sigaddset(&newmask, SIGUSR1);
    sigaddset(&newmask, SIGUSR2);
    sigaddset(&newmask, SIGALRM);
    
    sigprocmask(SIG_BLOCK, &newmask, &oldmask);
    printf("SIGUSR is blocked
");
    kill(getpid(), SIGUSR2);
    kill(getpid(), SIGUSR1);
    kill(getpid(), SIGALRM);
    
    sigprocmask(SIG_SETMASK, &oldmask, NULL);
}

奇怪,书上说signal有bug,信号会执行很多次,但我这里没问题啊?

sigaction的

#include<stdlib.h>
#include<signal.h>
static void sig_usr1(signo)
{
    printf("SIGUSR1 function
");
}
static void sig_usr2(signo)
{
    printf("SIGUSR2 function
");
}
static void sig_alarm(signo)
{
    printf("SIGALRM function
");
}
int main(void)
{
    struct sigaction act1, act2, act3;
    act1.sa_handler = sig_usr1;
    sigemptyset(&act1.sa_mask);
    act2.sa_handler = sig_usr2;
    sigemptyset(&act2.sa_mask);
    act3.sa_handler = sig_alarm;
    sigemptyset(&act3.sa_mask);    

    //安装信号处理函数
    sigaction(SIGUSR1, &act1, NULL);
    sigaction(SIGUSR2, &act2, NULL);
    sigaction(SIGALRM, &act3, NULL);
    
    sigset_t newmask, oldmask;
    sigemptyset(&newmask);   //掩码置空
    sigaddset(&newmask, SIGUSR1);
    sigaddset(&newmask, SIGUSR2);
    sigaddset(&newmask, SIGALRM);
    
    sigprocmask(SIG_BLOCK, &newmask, &oldmask);
    printf("SIGUSR is blocked
");
    kill(getpid(), SIGUSR2);
    kill(getpid(), SIGUSR1);
    kill(getpid(), SIGALRM);
    
    sigprocmask(SIG_SETMASK, &oldmask, NULL);
}

效果一样的

原文地址:https://www.cnblogs.com/dplearning/p/4684293.html