从信号发送管道读取

时间:2014-05-04 13:23:14

标签: c process pipe

我想:

家长流程:

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

子进程:

  • 捕获信号后读取数据。

这是我的试用版:

#include<stdio.h>
#include<string.h>
#include <stdlib.h>

#include <sys/types.h>
#include <sys/uio.h>
#include <fcntl.h>
#include <unistd.h> 
#include <signal.h>

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,代码可能真的搞砸了,请你好。

1 个答案:

答案 0 :(得分:2)

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

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

其他一些事情:

  • 您不应多次关闭文件。文件描述符编号可能会在其他地方重复使用,甚至可能无意中关闭了您没有预料到的内容。

  • 请注意您正在撰写和阅读的数据。你正在编写一个char大小的内存,但是读入一个int。确保您真正想要的是什么,否则您将获得意想不到的价值。

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

  • 比处理文件时使用信号更好,您可以与poll()或select()调用同步(或者如果您的代码足够简单,只需在读取的文件上阻塞()...你的示例代码被重新分解以完全删除信号处理程序并且仍然以相同的方式工作,但是你的真实代码可能比这更复杂。)