从信号发送管道读取

我想要:

家长流程:

  • 将数据写入管道
  • 向子进程发送信号

儿童过程:

  • 捕获信号后读取数据。

这是我的试用版:

#include #include #include  #include  #include  #include  #include  #include  int fd[2]; //Handler - Exiting process, OR reading from pipe void sigHandler(int signumber){ if(signumber == SIGUSR1) { printf("SIGUSR1 catched.\n"); //So lets read from pipe int read_data = -1; close(fd[1]); read(fd[0], &read_data, sizeof(read_data)); //This printf never gets called printf("Received data: %s", read_data); } else { printf("SIGQUIT catched.\n"); exit(3); } } //This is handles parent process to NOT exit on sending a signal //maybe not the best workaround but i could only do this in this way. void sigDummy(int signumber){ printf("SigDummy catched\n"); } int main(){ fflush(stdout); pipe(fd); char option=-1; pid_t child_a; pid_t child_b; child_a = fork(); //A Child Proc which is not used atm, it will be if (child_a == 0) { signal(SIGQUIT ,sigHandler); signal(SIGUSR1 ,sigHandler); while(1) { //idle sleep(1); printf("child_a iddle work\n"); } } //Child B Proc for reading form the PIPE after got SIGUSR1 signal else { child_b = fork(); if (child_b == 0) { signal(SIGQUIT ,sigHandler); signal(SIGUSR1 ,sigHandler); while(1) { //idle sleep(1); printf("child_b iddle work\n"); } } //Parent Proc for writing to a pipe and sending signals to child B to read the pipe else { signal(SIGUSR1 ,sigDummy); //MENU WHILE while(option!=0){ scanf("%d", &option); printf("input was: %d\n", option); kill(child_b,SIGUSR1); close(fd[0]); write(fd[1], &option, sizeof(option)); } }//End of Menu while //Exiting child prcoesses then exiting parent prcoess if(option==0){ int status_a, status_b; waitpid(child_b, &status_b, WNOHANG|WUNTRACED); waitpid(child_a, &status_a, WNOHANG|WUNTRACED); kill(child_b,SIGQUIT); kill(child_a,SIGQUIT); } } return 1; } 

输出:

 child_b iddle work child_a iddle work child_b iddle work child_a iddle work child_b iddle work child_a iddle work child_b iddle work child_a iddle work 4 input was: 4 SigDummy catched SIGUSR1 catched. SIGUSR1 catched. //I wait here several seconds, child_a and b processes are not printing anything anymore.... 3 input was: 3 SigDummy catched 1 input was: 1 SigDummy catched 

如果我删除管道写管道读取部分我有很好的工作代码:

没有管道写入和读取的输出:

 child_a iddle work child_b iddle work 3 input was: 3 SigDummy catched SIGUSR1 catched. child_a iddle work SIGUSR1 catched. child_b iddle work child_a iddle work child_b iddle work 2 input was: 2 SigDummy catched SIGUSR1 catched. child_b iddle work SIGUSR1 catched. child_a iddle work child_b iddle work child_a iddle work 1 input was: 1 SigDummy catched SIGUSR1 catched. child_b iddle work SIGUSR1 catched. child_a iddle work child_b iddle work child_a iddle work 4 input was: 4 //Inputs are always catched with my signal handler func, and child processes does not stop printing. SigDummy catched SIGUSR1 catched. child_b iddle work SIGUSR1 catched. child_a iddle work child_b iddle work child_a iddle work child_b iddle work child_a iddle work 0 input was: 0 SigDummy catched SIGUSR1 catched. SIGQUIT catched. SIGUSR1 catched. SIGQUIT catched. Exiting 

我发现的方法在没有写 – 读管部分的情况下运行良好。 但在添加之后,它只是随机错误。

那么为什么我的代码行为在我尝试管道发送时的其他方式呢? 我刚开始学习c,代码可能真的搞砸了,请你好。

问题是printf("Received data: %s", read_data); 声明。 通过将%s放入格式字符串中, read_data变量将被视为指针并取消引用(您可能需要%d代替或类似)。

当您输入值4 。 您最终尝试访问地址0xffffff04 ,这通常会导致分段错误,但在信号处理程序的上下文中,它似乎只是默默地杀死子进程。

其他一些事情:

  • 您不应该多次关闭文件。 文件描述符编号可能会在别处重复使用,您甚至可能无意中关闭了您不期望的内容。

  • 小心你正在写和阅读的数据。 你正在编写一个char大小的内存,但是读入一个int。 确保这是你真正想要的,否则你会得到意想不到的价值。

  • 一般来说,信号处理程序不是做大量繁重工作的好地方。 许多操作在这里并不是非常安全,并且可能会干扰程序在以意外方式中断时所执行的操作。 通常最好使用信号处理程序简单地通知程序的其余部分需要注意的事情,并让主程序完成大部分工作。

  • 甚至比处理文件时使用信号更好,你可以与poll()或select()调用同步(或者如果你的代码很简单,只需用read()阻塞文件……你的示例代码重新考虑完全删除信号处理程序并仍然以相同的方式工作,但您的真实代码可能比这更复杂)。