在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;
}
(多敲多练)