【发布时间】:2019-01-18 20:28:11
【问题描述】:
我有 2 个程序:1) 父亲 2) 孩子。 当 父亲 收到 SIGINT (CTRL-C) 信号时,他的处理程序会向他的孩子发送一个 SIGTERM。问题是它经常(不总是,不知道为什么)在 SIGINT 之后在循环中显示此错误:
Invalid Argument
父亲的目标是创造一个孩子,然后活着准备处理 SIGINT。
父亲
#include "library.h"
static void handler();
int main(int argc, char* argv[]){
int value, que_id;
char str_que_id[10], **child_arg;
pid_t child_pid;
sigaction int_sa;
//Create message queue
do{
que_id = msgget(IPC_PRIVATE, ALL_PERM | IPC_CREAT);
}while(que_id == -1);
snprintf(str_que_id, sizeof(str_que_id), "%d", que_id);
//Set arguments for child
child_arg = malloc(sizeof(char*) * 3);
child[0] = "child";
child[1] = str_que_id;
child[2] = NULL;
//Set handler for SIGINT
int_sa.sa_handler = &handler;
int_sa.sa_flags = SA_RESTART;
sigemptyset(&int_sa.sa_mask);
sigaddset(&int_sa.sa_mask, SIGALRM);
sigaction(SIGINT, &int_sa, NULL);
//Fork new child
if(value = fork() == 0){
child_pid = getpid();
do{
errno = 0;
execve("./child", child_arg, NULL);
}while(errno);
}
//Keep alive father
while(1);
return 0;
}
static void handler(){
if(kill(child_pid, SIGTERM) != -1)
waitpid(child_pid, NULL, WNOHANG);
while(msgctl(que_id, IPC_RMID, NULL) == -1);
free(child_arg);
exit(getpid());
}
孩子的目标(目前仅在我的项目中)只是等待从消息队列传入的新消息。由于不会有任何消息,所以它会一直被屏蔽。
孩子
#include "library.h"
typedef struct _Msgbuf {
long mtype;
char[10] message;
} Msgbuf;
int main(int argc, char * argv[]){
int que_id;
//Recovery of message queue id
que_id = atoi(argv[1]);
//Set handler for SIGTERM
signal(SIGTERM, handler);
//Dynamic allocation of message
received = calloc(1, sizeof(Msgbuf));
while(1){
do{
errno = 0;
//This will block child because there won't be any message incoming
msgrcv(que_id, received, sizeof(Msgbuf) - sizeof(long), getpid(), 0);
if(errno)
perror(NULL);
}while(errno && errno != EINTR);
}
}
static void handler(){
free(received);
exit(getpid());
}
调用进程捕获一个信号。在这种情况下,系统调用失败,errno 设置为 EINTR。 (msgrcv() 在被信号处理程序中断后永远不会自动重新启动,无论在建立信号处理程序时 SA_RESTART 标志的设置如何。)
那么为什么它会循环打印那个错误呢?它应该在处理程序中退出,而不是在处理程序返回并且(因为 free(received) 之后)它没有找到将 errno 设置为 EINVAL 的消息缓冲区。
【问题讨论】:
-
除非你做一些特别的事情,否则 control-C 会杀死父母和孩子。所以我怀疑你有一个竞争条件:当父母试图杀死孩子时,孩子可能已经死了并且走了,导致
Invalid argument问题。 -
@SteveSummit 所以问题是父亲的处理程序没有必要杀死孩子。对吗?
-
@G.locurto 好吧,如果父母没有必要杀死孩子,那么在这种情况下,鉴于您描述了parent 作为“创建一个孩子,然后活着准备处理 SIGINT”。
-
@G.locurto 至少在 Unix 和 Linux 下,除非你做一些特别的事情,在这种情况下按下 control-C 会向所有进程发送 SIGINT。 (键盘信号会发送到当前进程组中的所有进程。除非你做一些特别的事情,否则调用
fork会得到一个与它的父进程在同一个进程组中的新进程。) -
@G.locurto 你必须设置一个
sig_atomic_t全局变量,你的应用程序的主循环会检查它。
标签: c unix signals posix handler