15_发送信号sigqueue()传参数和捕捉信号sigaction()传参

发送信号传参

igqueue函数对应kill函数,但可在向指定进程发送信号的同时携带参数
int sigqueue(pid_t pid, int sig, const union sigval value);成功:0;失败:-1,设置errno
           union sigval {
               int   sival_int;
               void *sival_ptr;
           };
    向指定进程发送指定信号的同时,携带数据。但,如传地址,需注意,不同进程之间虚拟地址空间各自独立,将当前进程地址传递给另一进程没有实际意义。

捕捉函数传参

int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
           struct sigaction {
               void     (*sa_handler)(int);
               void     (*sa_sigaction)(int, siginfo_t *, void *);
               sigset_t   sa_mask;
               int       sa_flags;
               void     (*sa_restorer)(void);
           };
    当注册信号捕捉函数,希望获取更多信号相关信息,不应使用sa_handler而应该使用sa_sigaction。但此时的sa_flags必须指定为SA_SIGINFO。siginfo_t是一个成员十分丰富的结构体类型,可以携带各种与信号相关的数据。
#if 0
siginfo_t {
           int      si_signo;     /* Signal number */
           int      si_errno;     /* An errno value */
           int      si_code;      /* Signal code */
           int      si_trapno;    /* Trap number that caused
                                     hardware-generated signal
                                     (unused on most architectures) */
           pid_t    si_pid;       /* Sending process ID */
           uid_t    si_uid;       /* Real user ID of sending process */
           int      si_status;    /* Exit value or signal */
           clock_t  si_utime;     /* User time consumed */
           clock_t  si_stime;     /* System time consumed */
           sigval_t si_value;     /* Signal value */其他Unix版本
           int      si_int;       /* POSIX.1b signal */posix
           void    *si_ptr;       /* POSIX.1b signal */posix
           int      si_overrun;   /* Timer overrun count;
                                     POSIX.1b timers */
           int      si_timerid;   /* Timer ID; POSIX.1b timers */
           void    *si_addr;      /* Memory location which caused fault */
           long     si_band;      /* Band event (was int in
                                     glibc 2.3.2 and earlier) */
           int      si_fd;        /* File descriptor */
           short    si_addr_lsb;  /* Least significant bit of address
                                     (since Linux 2.6.32) */
           void    *si_call_addr; /* Address of system call instruction
                                     (since Linux 3.5) */
           int      si_syscall;   /* Number of attempted system call
                                     (since Linux 3.5) */
           unsigned int si_arch;  /* Architecture of attempted system call
                                     (since Linux 3.5) */
           }
#endif
#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)

//使用信号用于父子进程间的通讯,子进程发送数据,父进程接收数据
#if 1
//用新的回到函数接受数据。。。。  
void myHandle_forsigaction(int signum, siginfo_t *s_t, void *p)
{
        int myint = 0;
        printf("recv signum : %d \n", signum);
        myint = s_t->si_value.sival_int;
        printf("%d, %d \n", myint, s_t->si_int );
        //printf("%s, %s \n", (char *)s_t->si_value.sival_ptr, (char *)s_t->si_ptr );
}

int test()
{
    pid_t   pid;
    int ret = 0;

    struct sigaction act;
    act.sa_sigaction = myHandle_forsigaction;
    sigemptyset(&act.sa_mask);
    act.sa_flags = SA_SIGINFO;// SA_SIGINFO表示能够使用参数传输数据
    //父进程注册信号处理函数
    if (sigaction(SIGINT, &act, NULL) < 0)
        ERR_EXIT("sigaction error");

    pid = fork();
    if (pid == -1){
        printf("fork err...\n");
        return 0;
    }

    if (pid == 0){
        int i = 0;  
      union sigval  mysigval;//注意是共用体,只能使用其中的一个成员
       mysigval.sival_int = 222;
       //mysigval.sival_ptr = "hello world";
        //kill(getppid(), SIGINT);//kill只能发送信号,却不能携带额外数据
        //带额外数据
        for (i=0; i<10; i++)
        {
            ret  = sigqueue(getppid(), SIGINT, mysigval);
            if (ret != 0)
            {
                printf("sigqueue .....\n");
                exit(0);
            }
            else
            {
                printf("sigqueue...successs\n");
                sleep(2);
            }
        }
    }
    else if (pid > 0)
    {
        for (;;)
            pause();
    }

    return 0;
}
#endif
/*
    测试可靠信号与不可靠信号
*/
#if 1

void myhandle(int signo)
{
    if(signo == SIGUSR1){
        //把SIGINT和SIGRTERM均添加到本进程的阻塞状态字中
        sigset_t bset;
        sigemptyset(&bset);
        sigaddset(&bset, SIGINT);
        sigdelset(&bset, SIGRTMIN);
      //解除阻塞SIG_UNBLOCK
        sigprocmask(SIG_UNBLOCK, &bset, NULL);
        printf("解除阻塞 recv sig SIGUSR1:%d \n", signo);

        //回复信号的默认状态
        //signal(SIGINT, SIG_DFL);

    }else if(signo == SIGINT || signo == SIGRTMIN){
            printf("recv sig num:%d \n", signo);

    }else {
        printf("其他信号recv sig num:%d \n", signo);
    }
}

 //sigval_t si_value;      /* Signal value */
 //int      si_int;       /* POSIX.1b signal */
 //void    *si_ptr;       /* POSIX.1b signal */

void  mysa_sigaction(int signo, siginfo_t * s_t, void *p)
{
    if(signo == SIGUSR1){
        //把SIGINT和SIGRTERM均添加到本进程的阻塞状态字中
        sigset_t bset;
        sigemptyset(&bset);
        sigaddset(&bset, SIGINT);
        sigdelset(&bset, SIGRTMIN);
      //解除阻塞SIG_UNBLOCK
        sigprocmask(SIG_UNBLOCK, &bset, NULL);
        printf("解除阻塞 recv sig SIGUSR1:%d \n", signo);

        //回复信号的默认状态
        //signal(SIGINT, SIG_DFL);

    }else if(signo == SIGINT || signo == SIGRTMIN){

        int myint = 0;
        myint = s_t->si_value.sival_int;
        printf("recv sig num:%d,信号携带的数据:%d, %d \n", signo, myint, s_t->si_int);     
    }else {
        printf("其他信号recv sig num:%d \n", signo);
    }
}

void test()
{
    pid_t pid;
    struct sigaction act;
#if 1
    act.sa_handler = myhandle;
    act.sa_flags = 0;
#else
    act.sa_sigaction = mysa_sigaction;  
    act.sa_flags = SA_SIGINFO;//用于额外数据传参必须设置
#endif
    //注册非实时信号处理函数
    if(sigaction(SIGINT, &act, NULL) < 0){
        ERR_EXIT("sigaction SIGINT");
    }

    //注册实时信号处理函数
    if(sigaction(SIGRTMIN, &act, NULL) < 0){
        ERR_EXIT("sigaction SIGRTMIN");
    }

        //注册用户自定义信号 SIGUSR1 处理函数
    if(sigaction(SIGUSR1, &act, NULL) < 0){
        ERR_EXIT("sigaction SIGUSR1");
    }

    //将SIGINT与SIGRTMIN均添加到本进程的阻塞状态字中
    sigset_t bset;
    sigemptyset(&bset);
    sigaddset(&bset, SIGINT);
    sigdelset(&bset, SIGRTMIN);
  //对信号进行阻塞SIG_UNBLOCK
    sigprocmask(SIG_BLOCK, &bset, NULL);

    //完成以上的信号设置后,才能进行fork操作,因为信号也有继承性
    pid = fork();
    if(pid == -1){
        ERR_EXIT("fork err");
    }
    if(pid == 0){
        int i = 0;
        int ret = 0;
        union sigval v;

    v.sival_int = 201;

     //发送3次不稳定信号
    for ( i = 0; i < 3; i++)
    {
        //向父进程发送带参数信号
        ret = sigqueue(getppid(), SIGINT, v);
        if(ret != 0){
            printf("发送不可靠信号 SIGINT 2 失败 ret: %d\n", ret);
            exit(0);
        }else{
            printf("发送不可靠信号 SIGINT 2 ok\n");    
        }
    }

     v.sival_int = 301;
      //发送3次稳定信号
    for ( i=0; i<3; i++)
    {
        //向父进程发送带参数信号
        ret = sigqueue(getppid(), SIGRTMIN, v);
        if(ret != 0){
            printf("发送可靠信号 SIGRTMIN 34 失败 ret: %d\n", ret);
            exit(0);
        }else{
            printf("发送可靠信号 SIGRTMIN 34 ok\n");  
        }
    }

    //向父进程发送SIGUSR1
    kill(getppid(), SIGUSR1);   
    }

    //父进程在这死循环
    while (1) {
        sleep(1); 
    }
    printf("main.....\n");
}
    /*
        hzmct@U-64:/study/linuxtest/day02/02signal$ ./dm03_sigqueuc
        发送不可靠信号 SIGINT 2 ok
        发送不可靠信号 SIGINT 2 ok
        发送不可靠信号 SIGINT 2 ok
        发送可靠信号 SIGRTMIN 34 ok
        发送可靠信号 SIGRTMIN 34 ok
        发送可靠信号 SIGRTMIN 34 ok
        recv sig num:34 
        recv sig num:34 
        recv sig num:34 
        recv sig num:2 
        解除阻塞 recv sig SIGUSR1:10 
        ^C
        ^C
 携带数据运行结果如下
        hzmct@U-64:/study/linuxtest/day02/02signal$ ./dm03_sigqueuc
        发送不可靠信号 SIGINT 2 ok
        发送不可靠信号 SIGINT 2 ok
        发送不可靠信号 SIGINT 2 ok
        发送可靠信号 SIGRTMIN 34 ok
        发送可靠信号 SIGRTMIN 34 ok
        发送可靠信号 SIGRTMIN 34 ok
        recv sig num:34,信号携带的数据:301, 301 
        recv sig num:2,信号携带的数据:201, 201 
        解除阻塞 recv sig SIGUSR1:10 
        recv sig num:34,信号携带的数据:301, 301 
        recv sig num:34,信号携带的数据:301, 301 
        ^C
        ^C
        从运行结果可以看出,解除对SIGINT和SIGRTMIN后,不可靠信号只到达一次,
 而可靠信号支持排队顺序依次到达。
        按道理,解除对SIGINT的阻塞后,再按下crtl+c程序应该退出,可是程序没有退出。
 因此在信号处理函数中,使用signal()函数恢复SIGINT的默认值,效果还是一样!!
*/
#endif
/*
    性能测试
    可靠信号linux内核是要缓存的,缓存的大小需要通过ulimit -a 查看
    不可靠信号只缓存1*/
#if 1
void myhandle(int num, siginfo_t *info , void * p)
{
        if (num == SIGUSR1)
        {
        //把SIGINT和SIGRTMIN均添加到本进程的阻塞状态字中
            sigset_t bset;
            sigemptyset(&bset);
            sigaddset(&bset, SIGINT);
            sigaddset(&bset, SIGRTMIN);

            sigprocmask(SIG_UNBLOCK, &bset, NULL);
            printf("解除阻塞 recv sig num:%d \n", num);     
        }
        else if (num == SIGINT || num== SIGRTMIN)
        {   
            printf("recv sig num:%d, 收到的数据是,%d\n",num, info->si_value.sival_int);
        }
        else
        {
            printf("其他recv sig num:%d \n",  num);
            printf("收到的数据是,%d\n",info->si_value.sival_int);
        }
}

void test()
{
    pid_t   pid;
    struct sigaction act;
    act.sa_sigaction = myhandle;
    act.sa_flags = SA_SIGINFO;

    //注册非实时信号 处理函数
    if ( sigaction(SIGINT, &act, NULL) <0 )
    {
        ERR_EXIT("sigaction SIGINT");
    }
    //注册实时信号的处理函数
    if ( sigaction(SIGRTMIN, &act, NULL) <0 )
    {
        ERR_EXIT("sigaction SIGINT");
    }

    //注册了一个用户自定义信号SIGUSR1 处理函数
    if ( sigaction(SIGUSR1, &act, NULL) <0 )
    {
        ERR_EXIT("sigaction SIGINT");
    }

    //把SIGINT和SIGRTMIN均添加到本进程的阻塞状态字中
    sigset_t bset;
    sigemptyset(&bset);
    sigaddset(&bset, SIGINT);
    sigaddset(&bset, SIGRTMIN);

    sigprocmask(SIG_BLOCK, &bset, NULL);

    pid = fork();
    if (pid == -1)
    {
        ERR_EXIT("fork err");
    }

    if (pid == 0)
    {
        int i = 0;
        int ret = 0;
        union sigval v;
        v.sival_int = 0;

#if 0
//可靠信号 性能测试
        for (i=0; i<900*1024; i++) //8K
        {
            v.sival_int ++;
            ret = sigqueue(getppid(), SIGRTMIN, v);
            if(ret != 0){
            printf("发送可靠信号 SIGRTMIN 34 失败 ret: %d\n", ret);
            //exit(0);
        }else{
            printf("发送可靠信号 SIGRTMIN 34 ok, %d\n", i);   
        }   
        }
#else 
//不可靠信号性能测试
for (i=0; i<900*1024; i++) //8K
        {
            v.sival_int ++;
            //ret = sigqueue(getppid(), SIGRTMIN, v);
            ret = sigqueue(getppid(), SIGINT, v);
            if(ret != 0){
            printf("发送不可靠信号 SIGINT 2 失败 ret: %d\n", ret);
            //exit(0);
        }else{
            printf("发送不可靠信号 SIGINT 2  ok, %d\n", i);    
        }   
        }

#endif  
        sleep(1);
        kill(getppid(), SIGUSR1);
    }

    while(1)
    {
        sleep(1);
    }
    printf("main....\n");
}
/*
    linux内核调优,需要看这个
    hzmct@U-64:/study/linuxtest/day02/02signal$ ulimit -a
    core file size          (blocks, -c) 0
    data seg size           (kbytes, -d) unlimited
    scheduling priority             (-e) 0
    file size               (blocks, -f) unlimited
    pending signals                 (-i) 3773
    max locked memory       (kbytes, -l) 64
    max memory size         (kbytes, -m) unlimited
    open files                      (-n) 65536
    pipe size            (512 bytes, -p) 8
    POSIX message queues     (bytes, -q) 819200
    real-time priority              (-r) 0
    stack size              (kbytes, -s) 8192
    cpu time               (seconds, -t) unlimited
    max user processes              (-u) 3773 //未决信号集的最大数
    virtual memory          (kbytes, -v) unlimited
    file locks                      (-x) unlimited

子进程休眠1s的结果
    hzmct@U-64:/study/linuxtest/day02/02signal$ ./dm03_sigqueuc
    recv sig num:34, 收到的数据是,1
    recv sig num:34, 收到的数据是,2
    recv sig num:34, 收到的数据是,3
    recv sig num:34, 收到的数据是,4
    recv sig num:34, 收到的数据是,5
    recv sig num:34, 收到的数据是,6
    recv sig num:34, 收到的数据是,7
    recv sig num:34, 收到的数据是,8
    recv sig num:34, 收到的数据是,9
    recv sig num:34, 收到的数据是,10
    解除阻塞 recv sig num:10 

    数字的大小取决于你的系统设置
    ulimit -i 
    hzmct@U-64:~$ ulimit -i
    3773

    recv sig num:34, 收到的数据是,3771
    recv sig num:34, 收到的数据是,3772
    recv sig num:34, 收到的数据是,3773
    解除阻塞 recv sig num:10 
*/
#endif

int main()
{
    test();
    return 0;   
}

猜你喜欢

转载自blog.csdn.net/WUZHU2017/article/details/81915304