sigqueue:给指定pid的进程发送信号sig,并且携带数据(数据存放在value参数中)
int sigqueue(pid_t pid, int sig, const union sigval value);
用于携带数据
union sigval {
int sival_int;
void *sival_ptr;
};
使用sigaction
处理sigqueue
发来的信号
[1] 定义sigaction的信号处理函数,用来接收
sigqueue函数发来的数据:接收的数据存放在siginfo_t结构体的si_value变量
中
void handler(int signum, struct siginfo_t* s_t, void* ptr)
{
printf(" param = %d\n",s_t->si_int);
}
详细介绍:struct siginfo_t 结构体(包含了信号产生原因的有关信息)
struct siginfo_t{
int si_signo; // 接收到的信号
int si_errno; // if 非0,errno value from <errno.h>
int si_code; // 补充信息(取决于signal)
pid_t si_pid; // sending process ID
uid_t si_uid; // sending process real user ID
void *si_addr; // address that caused the fault
int si_status;// exit value or signal number
union sigval si_value; // application-specific value
}
union sigval si_value{
int sival_int; //传递整数值
void* sival_ptr; //传递一个指针值
}
[2] 定义并初始化sigaction的第二个参数act变量
struct sigaction act;
sigemptyset(&act.sa_mask); // 清空信号屏蔽集合
act.sa_flags=SA_SIGINFO; // 设置SA_SIGINFO标志
act.sa_sigaction=handler; // 回调函数
[3] 调用sigaction函数注册XXX信号:sigaction(XXX,&act
, NULL);
[4] 给指定进程,通过sigqueue函数发送
[带有数据的XXX信号]
union sigval value;
value.sival_int=24; //数据被s_t->si_int接收到
sigqueue(pid,XXX,value);
示例代码
程序功能
1.父进程创建子进程1和子进程2
2.子进程1给子进程2发送可靠信号,并传送额外数据(子进程1的pid*2)
3.子进程2接收到可靠信号的值后,并将接收的值发送给父进程,父进程把接收的值打印
程序实现技巧
1.在父进程中可以通过 [缓存数组] 得到所有子进程的进程ID
2.[缓存数组]中的数据,在父进程/子进程1/子进程2中是相互独立的
step1:子进程1要发送数据给子进程2(但是子进程1无法知道子进程2的进程ID),因此需要父进程先将子进程2的PID发送给子进程1
step2:子进程1接收到父进程发来的[数据(子进程2的PID)]后,在信号处理函数中,修改[缓存数组]
step3:子进程1将[数据(子进程1的PID*2)]发送给子进程2
step4:子进程2获得数据后,修改自己的message
setp5:子进程将message发送给父进程
step6:父进程接收到message后,打印接收到的message
pid_t pidArray[10];
pid_t message;
void handler(int signum, siginfo_t* s_t, void *ptr){
if(signum==SIGRTMIN+1){
printf(" process1 recv SIGRTMIN+1,value=%d\n",s_t->si_value.sival_int);
pidArray[1]=s_t->si_value.sival_int; //step2:子进程1获得子进程2的进程ID后,修改自己的缓存数组pidArray[1]
}
else if(signum==SIGRTMIN+2){
printf(" process2 recv SIGRTMIN+2,value=%d\n",s_t->si_value.sival_int);
message=s_t->si_value.sival_int; //step4:子进程2获得数据后,修改自己的message
}
else if(signum==SIGRTMIN+3){
printf(" parent recv SIGRTMIN+3,value=%d\n",s_t->si_value.sival_int); //step6:父进程接收到message后,打印接收到的message
}
}
int main(){
struct sigaction act;
act.sa_flags=SA_SIGINFO;
act.sa_sigaction=handler;
sigemptyset(&act.sa_mask);
sigaction(SIGRTMIN+1,&act,NULL);
sigaction(SIGRTMIN+2,&act,NULL);
sigaction(SIGRTMIN+3,&act,NULL);
int thread_num=2;
pid_t pid;
int i;
for(i=0;i<thread_num;i++){
pidArray[i]=pid=fork();
if(pid==0){
break;
}
}
if(i==0){ //process1
sleep(5);
union sigval value;
value.sival_int=getpid()*2;
printf("process1 ---> process2:[ SIGRTMIN+2: message]\n");
sigqueue(pidArray[1],SIGRTMIN+2,value); //step3:子进程1将[数据(子进程1的进程ID*2)]发送给子进程2
}
if(i==1){ //process2
sleep(10);
union sigval value;
value.sival_int=message;
printf("process2 ---> parent:[ SIGRTMIN+3: message]\n");
sigqueue(getppid(),SIGRTMIN+3,value); //setp5:子进程将message发送给父进程
}
if(i==thread_num){ //parent process
union sigval value;
value.sival_int=pidArray[1];
printf("parent ---> process1:[ SIGRTMIN+1:pidArray[1] ]\n");
sigqueue(pidArray[0],SIGRTMIN+1,value); // step1:父进程将子进程2的进程ID发送给子进程1
//wait child process
int status;
pid_t ret;
while((ret=waitpid(-1,&status,WNOHANG))!=-1){
if(ret==0)
continue;
printf("wait %d pid",ret);
if(WIFEXITED(status))
printf("exit,status=%d\n",WEXITSTATUS(status));
else if(WIFSIGNALED(status))
printf("signal,status=%d\n",WTERMSIG(status));
}
}
return 0;
}
[gjw@localhost homework]$ ./work
parent ---> process1:[ SIGRTMIN+1:pidArray[1] ]
process1 recv SIGRTMIN+1,value=36534
process1 ---> process2:[ SIGRTMIN+2: message]
process2 recv SIGRTMIN+2,value=73066
process2 ---> parent:[ SIGRTMIN+3: message]
parent recv SIGRTMIN+3,value=73066
wait 36533 pidexit,status=0
wait 36534 pidexit,status=0