我有一个父进程,它使用循环中的fork创建了16个子进程。最终,每个子进程都会发送一个SIGUSR1信号,该信号由父进程中的处理程序函数处理。
我的问题是这样的 - 一些孩子发送信号,而来自另一个孩子的信号被处理。我读到处理程序函数然后停止并处理新信号,忽略其正在处理的当前信号。
我试图通过在处理程序函数的开头发送:kill(0,SIGSTOP)
来解决这个问题,但看起来这也停止了父进程。有没有办法只向孩子发送这个信号?
如果不可能,我的目标可以使用wait, waitpid and kill
实现吗?
添加了下面的代码,我省略了诸如检查读取,打开等返回值之类的内容。
处理程序函数:
void my_signal_handler( int signum, siginfo_t* info, void* ptr)
{
kill(0, SIGSTOP);
int sonPid = info->si_pid;
char* pipeName = malloc(14 + sizeof(int));//TODO ok?
sprintf(pipeName, "//tmp//counter_%d" , (int) sonPid); //TODO double //?
size_t fdPipe = open(pipeName, O_RDONLY);
int cRead;
int countRead = read(fdPipe,&cRead,sizeof(int));
COUNT+= cRead;
kill(0, SIGCONT);
return;
}
创建子进程:
struct sigaction new_action;
memset(&new_action, 0, sizeof(new_action));
new_action.sa_handler = my_signal_handler;
new_action.sa_flags = SA_SIGINFO;
if( 0 != sigaction(SIGUSR1, &new_action, NULL) )
{
printf("Signal handle registration failed. %sn", strerror(errno));
return -1;
}
for(int i=0; i<16; i++){
pid_t cpid = fork();
if(cpid == 0) // child
{
execv("./counter",argvv); // some arguments to the function
printf("execv failed: %sn", strerror(errno));
return -1;
}
else{
continue;
}
孩子们的计数器程序,简而言之,它计算字符counc
在文件的某些部分中的外观,然后将其打印到管道中。
int main(int argc, char** argv){
int counter = 0;
char counc = argv[1][0];
char* filename = argv[2];
off_t offset = atoll(argv[3]);
ssize_t length = atoll(argv[4]);
int fd = open(filename, O_RDWR | O_CREAT);
char* arr = (char*)mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset);
for(int i=0; i<length; i++){
if(arr[i] == counc){
counter++;
}
}
pid_t proid = getpid();
pid_t ppid = getppid();
char* pipeName = malloc(14 + sizeof(pid_t));
sprintf(pipeName, "//tmp//counter_%d" , (int) proid);
size_t fdPipe = mkfifo(pipeName, 0777);
int didopen = open(pipeName,O_WRONLY);
size_t wrote = write(fdPipe,&counter , 1 );
if(wrote < 0){
printf(OP_ERR, strerror( errno ));
return errno;
}
kill(ppid, SIGUSR1);
//close the pipe and unmap the array
return 1;
}
如果我正确理解了你的问题,你分别在父亲和孩子中遇到了所需的信号功能问题。如果这不是您的情况,请纠正我。
如果你的问题是这样的,你可以简单地创建一些if
语句,以测试fork()
调用返回的pid
,然后仅在你是父亲时才执行。 所以...
if (pid == 0)
//ChildProcess();
// do nothing!
else
//ParentProcess();
// do something!
请注意,您必须将size_t pid
定义为全局变量,以便在您正在实现的主函数和信号处理程序函数中可见!
除了其他人已经指出的关于在信号处理程序中使用非异步安全函数的内容之外,我将冒昧地猜测问题出在这两件事之一:
- 您错误地假设通过
kill
发送的信号排队等待它们发送到的进程。它们不会排队(除非您在支持它的操作系统上使用sigqueue
);而是更新目标进程的挂起(尚未处理)信号集。请参阅 C 中的信号队列。或 - 您在不支持"可靠信号语义"的操作系统上运行此代码。请参阅男人 3 sysv_signal以获取见解(恐怖),例如:
然而,sysv_signal()为System V提供了不可靠的信号语义,即:a)当调用处理程序时,信号的处置被重置为默认值;b)在信号处理程序执行时,信号的进一步实例的传递不会被阻塞;