• 实时信号与sigqueue函数


    一、sigqueue函数

    功能:新的发送信号系统调用,主要是针对实时信号提出的支持信号带有参数,与函数sigaction()配合使用。
    原型:int sigqueue(pid_t pid, int sig, const union sigval value);
    参数:
     sigqueue的第一个参数是指定接收信号的进程id,第二个参数确定即将发送的信号,第三个参数是一个联合数据结构union sigval,指定了信号传递的参数,即通常所说的4字节值。
    返回值:成功返回0,失败返回-1 

    typedef union sigval
     { 
    int sival_int; 
    void *sival_ptr; 
    }sigval_t; 

     

    sigqueue()比kill()传递了更多的附加信息,但sigqueue()只能向一个进程发送信号,而不能发送信号给一个进程组。

    写两个小程序测试一下:

    首先是接收信号:

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
     
    /*************************************************************************
        > File Name: process_.c
        > Author: Simba
        > Mail: dameng34@163.com
        > Created Time: Sat 23 Feb 2013 02:34:02 PM CST
     ************************************************************************/
    #include<sys/types.h>
    #include<sys/stat.h>
    #include<unistd.h>
    #include<fcntl.h>
    #include<stdio.h>
    #include<stdlib.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 *);


    int main(int argc, char *argv[])
    {
        struct sigaction act;
        act.sa_sigaction = handler; //sa_sigaction与sa_handler只能取其一
        //sa_sigaction多用于实时信号,可以保存信息
        sigemptyset(&act.sa_mask);
        act.sa_flags = SA_SIGINFO; // 设置标志位后可以接收其他进程
        // 发送的数据,保存在siginfo_t结构体中

        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 data=%d ",
               sig, info->si_value.sival_int, info->si_int);

    }

    在前面的《信号捕捉与sigaction函数》中说过,sa_sigaction与SA_SIGINFO要配合使用,如上所示,siginfo_t 结构体也可以参见这篇文章。

     

    然后是信号发送:

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
     
    /*************************************************************************
        > File Name: process_.c
        > Author: Simba
        > Mail: dameng34@163.com
        > Created Time: Sat 23 Feb 2013 02:34:02 PM CST
     ************************************************************************/
    #include<sys/types.h>
    #include<sys/stat.h>
    #include<unistd.h>
    #include<fcntl.h>
    #include<stdio.h>
    #include<stdlib.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 val;
        val.sival_int = 100;
        sigqueue(pid, SIGINT, val); // 只可以发信号给某个进程,而不能是进程组

        return 0;

    }

    测试如下:

    先运行recv程序:

    simba@ubuntu:~/Documents/code/linux_programming/APUE/signal$ ./sigqueue_recv 

    再ps出recv进程的pid,然后运行send程序:

    simba@ubuntu:~/Documents/code/linux_programming/APUE/signal$ ./sigqueue_send 3323

    则recv进程会输出一条recv语句,当然我们也可以ctrl+c 给自己发送信号,如下所示,结果是一样的。

    recv a sig=2 data=100 data=100
    ^Crecv a sig=2 data=100 data=100
    ^Crecv a sig=2 data=100 data=100

    ......................................................

    需要提醒一下的是siginfo_t 结构体的两个参数(int  si_int;   /* POSIX.1b signal */     void  *si_ptr;  /* POSIX.1b signal */)的值也会与si_value 一致,取决于发送的是sival_int 还是 sival_ptr。

     

    二、实时信号与不可靠信号的区别

    下面通过程序来说明区别,主要就是实时信号支持排队不会丢失。(实时信号还有一个特点,即到达的顺序是可以保证的)

    先是recv程序:

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
     
    #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)
        {
            sigset_t s;
            sigemptyset(&s);
            sigaddset(&s, SIGINT);
            sigaddset(&s, SIGRTMIN);
            sigprocmask(SIG_UNBLOCK, &s, NULL);
        }
    }

    在主函数中将SIGINT和SIGRTMIN信号加入信号屏蔽字,只有当接收到SIGUSR1信号时才对前面两个信号unblock。需要注意的是如《信号的未决与阻塞》中说的一样:如果在信号处理函数中对某个信号进行解除阻塞时,则只是将pending位清0,让此信号递达一次(同个实时信号产生多次进行排队都会抵达),但不会将block位清0,即再次产生此信号时还是会被阻塞,处于未决状态。

     

    接着是send程序:

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
     
    /*************************************************************************
        > File Name: sigrtime_send.c
        > Author: Simba
        > Mail: dameng34@163.com
        > Created Time: Sat 23 Feb 2013 02:34:02 PM CST
     ************************************************************************/
    #include<sys/types.h>
    #include<sys/stat.h>
    #include<unistd.h>
    #include<fcntl.h>
    #include<stdio.h>
    #include<stdlib.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 val;
        val.sival_int = 100;
        sigqueue(pid, SIGINT, val); // 不可靠信号不会排队,即会丢失
        sigqueue(pid, SIGINT, val);
        sigqueue(pid, SIGINT, val);
        sigqueue(pid, SIGRTMIN, val); //实时信号会排队,即不会丢失
        sigqueue(pid, SIGRTMIN, val);
        sigqueue(pid, SIGRTMIN, val);
        sleep(3);
        kill(pid, SIGUSR1);

        return 0;

    }

    先是运行recv程序:

    simba@ubuntu:~/Documents/code/linux_programming/APUE/signal$ ./sigrtime_recv2

    接着ps出recv进程的pid,运行send程序:

    simba@ubuntu:~/Documents/code/linux_programming/APUE/signal$ ./sigrtime_send 4076

    在send程序中连续各发送了SIGINT和SIGRTMIN信号3次,接着睡眠3s后使用kill函数发送SIGUSR1信号给recv进程,此时recv进程会输出如下:

    recv a sig=34
    recv a sig=34
    recv a sig=34
    recv a sig=2

    即实时信号支持排队,3个信号都接收到了,而不可靠信号不支持排队,只保留一个信号。

     

    参考:《APUE》

  • 相关阅读:
    设计模式_EventObject和EventListener
    设计模式_Observable与Observer
    zooKeeper_《ZooKeeper官方指南》一致性保障
    thread_为什么多线程是个坏主意
    gtk+学习笔记(三)
    linux c下输入密码不回显
    浮点数在计算机内存中的存储方式
    gtk+学习笔记(二)
    linux下c图形化编程之gtk+2.0简单学习
    关于字符串排序合并的问题
  • 原文地址:https://www.cnblogs.com/alantu2018/p/8477295.html
Copyright © 2020-2023  润新知