• 【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);
    }

    效果一样的

  • 相关阅读:
    linux 下查看网速的方法 (不需要安装任何软件)
    Raspberry Pi Kernel Compilation 内核编译官方文档
    Kernel compiling for Pi 2
    从源码编译rpi的内核
    设备驱动调试和移植的一般方法
    爸爸的歌
    表扬?批评?
    日历插件js,jquery
    zepto jquery和zepto的区别?
    怎么学习PS快?
  • 原文地址:https://www.cnblogs.com/dplearning/p/4684293.html
Copyright © 2020-2023  润新知