Linux 信号(三) —— 强大的sigaction

在Linux中,对于信号的收发有着两组函数

1、入门版

        发送函数:int kill(pid_t pid, int sig);

        接收函数:sighandler_t signal(int signum, sighandler_t handler);

这组函数在之前的文章中已有讲解

2、高级版

        发送函数:  int sigqueue(pid_t pid, int sig, const union sigval value);

        接收函数:  int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

一、入门版与高级版的区别

        入门版的函数只能发送哪种信号,并不能在发送信号的同时把我们关心的一些数据也一同发过去,这就有点类似于,别人在门口敲门却一直不说话,就一个劲的在那里敲,这样是不是显得有点鸡肋,这就使得入门版的函数只能适用于一些简单的情景下。

        而高级版除了具备入门版的功能外,还能连同数据一起发送、设置信号是否阻塞,当信号中断了进程的某个系统调用,系统是否自动启动该系统调用。 比如:需要你输入一些数据(scanf),但是这时进来了个信号被中断了,如果设置了系统能自动启动该系统调用,则执行完信号处理函数时会继续执行之前的scanf。

二、详解高级版函数

 1、 发送函数 : int sigqueue(pid_t pid, int sig, const union sigval value);

        pid : 目标进程号

        sig : 发送的信号类型

        value : 要发送的数据,联合体

union sigval {
               int   sival_int;           // 整数 
               void *sival_ptr;        // 字符串
          };

 2、接收函数:  int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

#include <signal.h>

int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

struct sigaction {

                         void       (*sa_handler)(int);        //信号处理程序,不接受额外数据,SIG_IGN 为 忽 略,SIG_DFL 为默认动作,(这个实际上就是入门版的handler函数)        

                         void       (*sa_sigaction)(int, siginfo_t *, void *);         //信号处理程序,能够接受额外数据和sigqueue配合使用  (在高级版中,主要是用这个 ),第三个参数好像暂时来说没什么作用。

                        sigset_t   sa_mask;        // 阻塞关键字的信号集

                        int        sa_flags;        //影响信号的行为SA_SIGINFO表示能够接受数据 ,SA_RESTART表示能够自启动,当然还有其他类型的标志

 };

//回调函数句柄sa_handler、sa_sigaction只能任选其一

mask默认情况下是阻塞的作用,即在处理一个信号时,如果还有其他信号到来,就让刚来的信号等待。

收到的数据、发送端的信息等都存放在下面这个结构体中

 代码示例:

接收端:

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

void handler(int sig,siginfo_t *info, void *context)
{
        printf("signal = %d\n",sig);

        printf("get the data is %d\n",info->si_int);  // 打印接收到的数据
        printf("get the data is %d\n",info->si_value.sival_int); // 打印接收到的数据
        /*
            printf("get the data is %s\n",(char *)info->si_value.sival_ptr);
            
            字符串的接收发需要用到共享内存,或者在同一进程内
            
        */
        printf("from the pid is %d\n",info->si_pid);  // 打印发送端的进程号

}

int main()
{
//       int sigaction(int signum, const struct sigaction *act,
//                     struct sigaction *oldact);
        char buf[10] ={0};

        struct sigaction act;
        act.sa_sigaction = handler;
        sigaddset(&act.sa_mask, 15);   // 15号信号加入到阻塞中
        //act.sa_flags = SA_RESTART;
        act.sa_flags = SA_SIGINFO | SA_RESTART;   // 能过接受数据和自启动

        sigaction(2,&act,NULL);
        sigaction(15,&act,NULL);

        printf("input: ");
        scanf("%s",buf);
        printf("buf is %s\n",buf);

        return 0;
}

                                                     

 发送端:

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

//int sigqueue(pid_t pid, int sig, const union sigval value);

int main(int argc, char **argv)
{
        if(argc != 3){
                printf("parameter error!\n");
                exit(0);
        }

        pid_t pid = atoi(argv[2]);   // 字符串转换成数字
        int signum = atoi(argv[1]);

        union sigval value1;
        value1.sival_int = 100;       // 发送的数据为 整数100
        sigqueue(pid,signum,value1);
        printf("the pid is %d\n",getpid());

        return 0;
}                                

(多敲多练)

  • 20
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值