gpt4 book ai didi

c - 信号处理问题

转载 作者:太空狗 更新时间:2023-10-29 15:42:19 31 4
gpt4 key购买 nike

fork 调用后,我有一位父亲必须将 sigusr1 或 sigusr2(基于“cod”变量的值)发送给他的 child 。 child 必须在接收 sigusr1 或 sigusr2 之前安装适当的处理程序。为此,我暂停父亲等待 child 向他发出信号,告诉他他已经完成了处理程序的安装。父亲由 sigusr1 发出信号,并且此信号的处理程序在 fork 调用之前安装。然而,父亲似乎无法从暂停中返回,这让我觉得他实际上从未调用过 sigusr1 处理程序。

[...]

typedef enum{FALSE, TRUE} boolean;

boolean sigusr1setted = FALSE;
boolean sigusr2setted = FALSE;


void
sigusr1_handler0(int signo){
return;
}

void
sigusr1_handler(int signo){
sigusr1setted = TRUE;
}

void
sigusr2_handler(int signo){
sigusr2setted = TRUE;
}

int main(int argc, char *argv[]){
[...]

if(signal(SIGUSR1, sigusr1_handler0) == SIG_ERR){
perror("signal 0 error");
exit(EXIT_FAILURE);
}

pid = fork();
if (pid == 0){
if(signal(SIGUSR1, sigusr1_handler) == SIG_ERR){
perror("signal 1 error");
exit(EXIT_FAILURE);
}

if(signal(SIGUSR2, sigusr2_handler) == SIG_ERR){
perror("signal 2 error");
exit(EXIT_FAILURE);
}

kill(SIGUSR1, getppid()); // wake up parent by signaling him with sigusr1

// Wait for the parent to send the signals...
pause();

if(sigusr1setted){
if(execl("Prog1", "Prog1", (char*)0) < 0){
perror("exec P1 error");
exit(EXIT_FAILURE);
}
}

if(sigusr2setted){
if(execl("Prog2", "Prog2", (char*)0) < 0){
perror("exec P2 error");
exit(EXIT_FAILURE);
}
}

// Should'nt reach this point : something went wrong...
exit(EXIT_FAILURE);

}else if (pid > 0){
// The father must wake only after the child has done with the handlers installation

pause();

// Never reaches this point ...
if (cod == 1)
kill(SIGUSR1, pid);
else
kill(SIGUSR2, pid);

// Wait for the child to complete..
if(wait(NULL) == -1){
perror("wait 2 error");
exit(EXIT_FAILURE);
}

[...]

}else{
perror("fork 2 error");
exit(EXIT_FAILURE);
}
[...]

exit(EXIT_SUCCESS);
}

最佳答案

从评论中收集合理的答案 - 所以这从一开始就是 Community Wiki。 (如果 Oli 提供了答案,请投票给那个而不是这个!)

Oli Charlesworth给出了可能是问题核心的内容:

  • 我怀疑您产生了与预期方向相反的竞争条件。在 parent 到达 pause() 之前, child 将 SIGUSR1 发送给 parent .

ouah准确记下:

  • 信号处理程序和非处理程序代码(您的 bool 对象)之间共享的对象必须具有 volatile sig_atomic_t键入否则代码未定义。

也就是说,POSIX 比标准 C 允许在信号处理程序内部执行的操作更加宽松。我们可能还会注意到 C99 提供了 <stdbool.h>定义 bool类型。

楼主评论:

I don't see how can I make sure that the parent goes in the pause() call first without using sleep() in the child (which guarantees nothing). Any ideas?

建议:使用usleep() (微 sleep ,或以微秒为单位的 sleep ),或 nanosleep() (以纳秒为单位休眠)?

或者使用不同的同步机制,比如:

  1. 父进程创建 FIFO;
  2. fork();
  3. child 打开 FIFO 进行写入(阻塞直到有读者);
  4. parent 打开 FIFO 进行读取(阻塞直到有写入者);
  5. 因为open()而被解锁调用返回,两个进程都简单地关闭 FIFO;
  6. 父级移除 FIFO。

注意两个进程之间没有通过FIFO进行数据通信;代码只是依靠内核来阻塞进程,直到有读取器和写入器,所以两个进程都已准备就绪。

另一种可能性是,父进程可以尝试 if (siguser1setted == FALSE) pause();减少竞争条件的窗口。但是,它只会缩小窗口;它不保证竞争条件不会发生。也就是说,墨菲定律适用,信号可能在测试完成时间和 pause() 时间之间到达。被执行。

所有这些都表明信号并不是一个很好的 IPC 机制。它们可用于 IPC,但实际上很少用于同步。

顺便说一下,没有必要测试任何exec*() 的返回值。函数族。如果系统调用返回,则失败。

提问者又问:

Wouldn't it be better to use POSIX semaphores shared between processes?

信号量肯定是同步两个进程的另一种有效机制。因为我当然必须查看信号量的手册页,而我不看也能记住如何使用 FIFO,所以我不确定我是否真的会使用它们,但是创建和删除 FIFO 有其自身的一系列问题因此尚不清楚它是否以任何方式“更好”(或“更差”);只是不同。这是mkfifo() , open() , close() , unlink()对于 FIFO 与 sem_open() (或 sem_init() ),sem_post() , sem_wait() , sem_close() ,也许 sem_unlink() (或 sem_destroy() )用于信号量。您可能需要考虑使用 atexit() 注册“FIFO 删除”或“信号量清理”功能。以确保 FIFO 或信号量在尽可能多的情况下被破坏。但是,这可能是测试程序的 OTT。

关于c - 信号处理问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8693647/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com