• linux系统编程之信号(六)


    今天继续学习信号相关的知识,主要还是学习sigqueue另外信号发送函数,并配合上节学习的sigaction的用法,进入正题:

    sigqueue函数:
    sigval联合体:
    实际上sigval参数是用来进程间通信用的,实际上信号是一个很古老的进程间通信的一种手段,通过这个参数,可以从一个进程发送到另外一个进程,并且可以附带参数。下面以实际代码来说明sigqueue是如何传递数据的:
    这里需要编写一个进程发送信号和一个进程接收信号来说明sigqueue:
    接收信号:
    要想接收信号数据,则需要在sigaction上加入flag,也就是上节当中遗漏的一个知识点,查看man帮助:
     
     
    另外,还得注意,如果要想接收信号,需要用到sigaction的另外一个处理函数:
     
    具体接收代码如下sigaction_recv.c:
    #include <unistd.h>
    #include <sys/stat.h>
    #include <sys/wait.h>
    #include <sys/types.h>
    #include <fcntl.h>
    
    #include <stdlib.h>
    #include <stdio.h>
    #include <errno.h>
    #include <string.h>
    #include <signal.h>
    
    
    #define ERR_EXIT(m) 
        do 
        { 
            perror(m); 
            exit(EXIT_FAILURE); 
        } while(0)
    
    void handler(int, siginfo_t *, void *);//需要用带多个参数的handler
    
    int main(int argc, char *argv[])
    {
        struct sigaction act;
        act.sa_sigaction = handler;
        sigemptyset(&act.sa_mask);
        act.sa_flags = SA_SIGINFO;//设置该flags可以接收其它进程传过来的信号
    
        if (sigaction(SIGINT, &act, NULL) < 0)
            ERR_EXIT("sigaction error");
    
        for (;;)
            pause();
        return 0;
    }
    
    void handler(int sig, siginfo_t *info, void *ctx)
    {
        printf("recv a sig=%d data=%d
    ", sig, info->si_value.sival_int);//它实际上就是sigqueue的sigval联合体,并打印出传过来的整型值
    }
     
    发送信号:
    编写一个通过sigqueue向某进程发送信号并携带数据来达到进程间通讯的目的:
    sigaction_send.c:
    编译运行:
    先运行接收信号的程序:
    再运行进程发送程序,向该接收进程发送信号,先找到该接收进程号:
    然后进行我们写的信号发送程序:
    另外,数据的接收还可以用这种方式来打印:
    输出如下:
    为啥可以这样写呢?查看sigaction的帮助:
    所以通过这种方式就能达到进程间通讯的目的。
    接下来再演示一个不可靠与可靠信号的一个问题:可靠信号支持排队,不可靠信号是不支持排队的
    验证方法:
    ① 写一个接收程序,里面注册一个可靠信号,一个不可靠信号,并将其加入屏蔽字中进行阻塞,然后再注册一个解除这两个信号阻塞的信号,程序如下:
    sigaction_recv.c:
    #include <unistd.h>
    #include <sys/stat.h>
    #include <sys/wait.h>
    #include <sys/types.h>
    #include <fcntl.h>
    
    #include <stdlib.h>
    #include <stdio.h>
    #include <errno.h>
    #include <string.h>
    #include <signal.h>
    
    
    #define ERR_EXIT(m) 
        do 
        { 
            perror(m); 
            exit(EXIT_FAILURE); 
        } while(0)
    
    void handler(int);
    
    int main(int argc, char *argv[])
    {
        struct sigaction act;
        act.sa_handler = handler;
        sigemptyset(&act.sa_mask);
        act.sa_flags = 0;
    
        sigset_t s;
        sigemptyset(&s);
        sigaddset(&s, SIGINT);
        sigaddset(&s, SIGRTMIN);
        sigprocmask(SIG_BLOCK, &s, NULL);//将这两个信号都加入屏蔽字当中进行阻塞
        if (sigaction(SIGINT, &act, NULL) < 0)//注册一个不可靠信号
            ERR_EXIT("sigaction error");
    
        if (sigaction(SIGRTMIN, &act, NULL) < 0)//注册一个可靠信号
            ERR_EXIT("sigaction error");
    
        if (sigaction(SIGUSR1, &act, NULL) < 0)//注册一个解除阻塞信号的信号
            ERR_EXIT("sigaction error");
        for (;;)
            pause();
        return 0;
    }
    
    void handler(int sig)
    {
        if (sig == SIGINT || sig == SIGRTMIN)
            printf("recv a sig=%d
    ", sig);
        else if (sig == SIGUSR1)
        {//当接收到SIGUSR1信号时,则解除阻塞,这时被阻塞的SIGINT,SIGRTMIN信号就变为递达状态了,这时就可以观察两者的区别了
            sigset_t s;
            sigemptyset(&s);
            sigaddset(&s, SIGINT);
            sigaddset(&s, SIGRTMIN);
            sigprocmask(SIG_UNBLOCK, &s, NULL);
        }
    }

    ② 编写一个发送信号的程序,里面发送多个SIGINT可靠信号,多个SIGTMIN不可靠信号,并且延时几秒之后,再将发送SIGUSR1信号解除绑定,最终观察看SIGINT收到了几个,SIGTMIN收到了几个,具体代码如下:

    sigaction_send.c:

    #include <unistd.h>
    #include <sys/stat.h>
    #include <sys/wait.h>
    #include <sys/types.h>
    #include <fcntl.h>
    
    #include <stdlib.h>
    #include <stdio.h>
    #include <errno.h>
    #include <string.h>
    #include <signal.h>
    
    
    #define ERR_EXIT(m) 
        do 
        { 
            perror(m); 
            exit(EXIT_FAILURE); 
        } while(0)
    
    int main(int argc, char *argv[])
    {
        if (argc != 2)
        {
            fprintf(stderr, "Usage %s pid
    ", argv[0]);
            exit(EXIT_FAILURE);
        }
    
        pid_t pid = atoi(argv[1]);
        union sigval v;
        v.sival_int = 100;
        sigqueue(pid, SIGINT, v);
        sigqueue(pid, SIGINT, v);
        sigqueue(pid, SIGINT, v);//发送三个SIGINT不可靠信号
    
        sigqueue(pid, SIGRTMIN, v);
        sigqueue(pid, SIGRTMIN, v);
        sigqueue(pid, SIGRTMIN, v);//发送三个SIGTMIN可靠信号
        
        sleep(3);//休眠3秒,目的是让其多个信号进行阻塞
        
        kill(pid, SIGUSR1);//发送一个SIGUSR1信号进行解除阻塞,改用kill来发送,当然也可用sigqueue啦
        return 0;
    }

    编译运行:

    从运行结果来看,经过3秒之后,34号信号,也就是SIGRTMIN信号接收了三次,而2号信号SIGINT信号只接收了一次所以也论证了可靠信号是支持排队的,而不可靠信号是不支持排队的

    关于sigaction还有很多其它的用法,这个之后有需求再进行探索,好了,今天的内容就学到这,下节见!

  • 相关阅读:
    使用repeater tableb绑定数据库
    运用js脚本实现table自动添加、删除行
    asp.net ListBox单选、全选、清除等功能
    .net 使用webservice 技术的测试案例
    使用.Net三层架构实现Gridview增、删、改功能
    使用用户控件AspNetPager+Gridview实现分页功能
    silverlight+wcf+linq to sql访问数据
    javascript实现乘法表(本人是菜鸟)
    oracle创建主键自增字段
    C#作Windows服务获取运行目录的方法
  • 原文地址:https://www.cnblogs.com/webor2006/p/3758021.html
Copyright © 2020-2023  润新知