背景: 我编写了一个程序,其中“父级”创建了2个子进程(发送方和接收方)。我以这样的方式实现了子代,即当一个子代失败时,它会向父代发送信号(SIGUSR2)。当父级接收到该信号时,找到另一个进程(例如,如果“接收方”发送了该信号,则父级找到了相应的“发送方”进程)并向其发送SIGINT信号。此后,父级将创建2个新子级。在针对SIGINT的孩子的信号处理程序中,我进行了一些清理(关闭命名管道,释放堆内存并正常退出)。我让“接收者”子代始终将SIGUSR2发送给父代,然后退出,因此父代将不得不找到“发送者”子代,向其发送信号并一次又一次创建新子代。
问题: 问题在于,只有第一个“发送方”子级收到信号,而其他(新的“发送方”子级)停留在以非阻塞模式打开命名管道的过程中,永远不会退出。
因此,我在阻止模式下打开了命名管道,并且“发件人”卡在了那里。根据{{3}}的手册,在等待完成打开过程中收到信号时,函数返回-1,并且errno设置为EINTR。 但是看起来开放系统调用永远不会失败,信号也永远不会收到。
因此,在SIGUSR2的 parent 信号处理程序中,我将以下信号发送至与发送信号的“接收方”相对应的“发送方”进程:
int stat;
cout << "Going to kill " << pidINFO2->myPID << endl;
int ret = kill(pidINFO2->myPID,SIGINT);
if (ret==0) cout << "SIGNAL WAS SENT SUCCESSFULLY" <<endl;
waitpid(pidINFO2->myPID,&stat,0);
cout << "AFTER WAIT" << endl;
这是整个发件人孩子的代码:
#include <iostream>
#include <cstring>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
using namespace std;
#include "interface.h"
char* input_dirName, *common_dirName, *myID, *syncID, *buflen;
void SIGINT_handler(int signo)
{
cout << "INTO SENDER " << getpid() << " SIGNAL HANDLER" << endl;
/* Remove the pipe we created */
/* Make the name+path of the named pipe */
char fifoNamePath[4096];
strcpy(fifoNamePath,common_dirName);
strcat(fifoNamePath,"/");
strcat(fifoNamePath,myID);
strcat(fifoNamePath,"_to_");
strcat(fifoNamePath,syncID);
strcat(fifoNamePath,".fifo");
/* ------------------------------------ */
unlink(fifoNamePath);
/* -------------------------- */
delete[] input_dirName;
delete[] myID;
delete[] syncID;
delete[] common_dirName;
delete[] buflen;
exit(0);
}
int main(int argc, char* argv[])
{
cout << "INTO SENDER CHILD -> " << getpid() << endl;
struct sigaction term;
term.sa_handler = SIGINT_handler;
term.sa_flags = SA_RESTART;
sigfillset(&term.sa_mask);
if (sigaction(SIGINT, &term, NULL) == -1) {
perror("sigaction");
return EXIT_FAILURE;
}
common_dirName = new char[strlen(argv[1])+1];
strcpy(common_dirName,argv[1]);
input_dirName = new char[strlen(argv[2])+1];
strcpy(input_dirName,argv[2]);
myID = new char[strlen(argv[3])+1];
strcpy(myID,argv[3]);
syncID = new char[strlen(argv[4])+1];
strcpy(syncID,argv[4]);
buflen = new char[strlen(argv[5])+1];
strcpy(buflen,argv[5]);
/* Create and/or open the named pipes (FIFO) */
/* Make the name+path of the named pipe */
char fifoNamePath[4096];
strcpy(fifoNamePath,common_dirName);
strcat(fifoNamePath,"/");
strcat(fifoNamePath,myID);
strcat(fifoNamePath,"_to_");
strcat(fifoNamePath,syncID);
strcat(fifoNamePath,".fifo");
/* ------------------------------------ */
if (mkfifo(fifoNamePath,0777)!=0) //try to make the FIFO
{
if (errno != EEXIST) //if we get an error and that error is different than EEXIST, then we send a signal to the parent to try again with a new child
{
perror("Error: ");
delete[] input_dirName;
delete[] myID;
delete[] syncID;
delete[] common_dirName;
delete[] buflen;
kill(getppid(),SIGUSR2);
exit(0);
}
}
//if we don't get an error or if the error is EEXIST (which means that the fifo is already made by the other process) we open it
cout << "before open in " << getpid() << endl;
int fd;
if ( (fd = open(fifoNamePath, O_WRONLY)) == -1) //we try to open the fifo "read-only" in BLOCKING mode
{
perror("Error: ");
delete[] input_dirName;
delete[] myID;
delete[] syncID;
delete[] common_dirName;
kill(getppid(),SIGUSR2);
unlink(fifoNamePath);
exit(0);
}
cout << "Sender opened -> " << fifoNamePath << " on " << fd << endl;
char buffer[50] = "SOMETHING";
int rsize;
if ( ( rsize = write(fd,&buffer,strlen(buffer)+1) )==-1)
{
perror("Error: ");
exit(5);
}
close(fd);
/* --------------------------- */
cout << "send completed for " << syncID << endl;
delete[] input_dirName;
delete[] myID;
delete[] syncID;
delete[] common_dirName;
delete[] buflen;
kill(getppid(),SIGUSR1);
exit(0);
}
因此,我期望所有“发送方”子级都从父级接收SIGINT信号,但似乎只有第一个“发送方”收到了信号,而其他“发送方”却没有,尽管父级表明该信号已成功发送
我得到的实际输出是:(它们共享相同的终端。无论显示INTO *** CHILD的位置,都是指父级创建了2个新进程)
[child]INTO SENDER CHILD -> 23410
[child]INTO RECEIVER CHILD -> 23409
[child]before open in 23410
[parent]The process -> 23409 terminated with an error!
[parent]Going to kill 23410
[parent]SIGNAL WAS SENT SUCCESSFULLY
[child]INTO SENDER 23410 SIGNAL HANDLER
[parent]AFTER WAIT
[child]INTO RECEIVER CHILD -> 23413
[child]INTO SENDER CHILD -> 23414
[child]before open in 23414
[parent]The process -> 23413 terminated with an error!
[parent]Going to kill 23414
[parent]SIGNAL WAS SENT SUCCESSFULLY
并且终端卡在那里。 parent在waitpid上被阻止,并且 child在open上被阻止(我猜是因为它打印的是“ before open in 23414”,而不是在open system call之后的消息) 。 那么,为什么创建的第二个“发送方”没有收到父级的SIGINT信号,因为父级说它已发送(信号已成功发送)。
我在做什么错了?