C IPC等待孩子

时间:2010-04-29 23:11:01

标签: c ipc

所以我有一个创建子进程并执行命令的程序(例如,ls)。然后,父母将使用管道发送给孩子并从孩子那里取得。当我从命令行输入命令时,这很好用。

但是,当输入来自文件时,似乎孩子没有足够的时间来运行,并且从管道读取时我得到NULL - 即使会有来自它的信息。

如果没有使用sleep(),是否有更好的方法可以确保孩子在尝试阅读之前已经运行了?

非常感谢!

3 个答案:

答案 0 :(得分:2)

如果你没有将管道文件描述符设置为非阻塞,那么应该没有问题。管道上的任何读数都会阻塞,直到孩子产生输出;如果您需要响应多个文件描述符(例如,来自用户的标准输入和来自子进程的管道),请使用select()poll()

我假设fgets()返回NULL。这表示文件结束(意味着孩子已关闭管道的末尾)或错误。您可以使用feof()ferror()来检查哪些是真的。在错误情况下使用perror()来查看错误实际是什么。

答案 1 :(得分:1)

问题是你对孩子有多少控制?如果您自己编写孩子,那么您可以让孩子在已经开始的共享内存中设置一个标志(或触摸一个文件或任何你想要的痒),然后只有在你知道孩子在线运行它时才会这样做。

如果您无法控制孩子,仍然可以通过使用您自己的脚本包装孩子来实现上述解决方案,该脚本首先启动子项然后设置共享内存。这可以是一种形式shell脚本如下

#!/bin/sh

$CHILD
my_app_that_set_the_flag

最后另一种选择是继续等待从管道中获取NULL,显然这会导致无限循环,但如果你不能指望你总会在管道上得到一些东西

答案 2 :(得分:1)

您的父线程需要等到子项准备就绪才能尝试从管道读取。有几种方法可以做到这一点。

首先,您可以使用条件变量。声明两个线程都可以访问的变量并将其设置为0。当父母已准备好阅读时,您的子线程将其设置为1。父级将等到变量更改为1(使用while(!condvar) sleep(1);之类的内容),然后它将从管道中读取并将变量重置为0,以便子级知道父级完了。

另一种选择是使用一种进程间通信形式,例如signals。与条件变量方法类似,子线程将执行其工作,然后在完成时向父线程发送信号。父线程将一直等到它从管道读取之前收到信号,然后它可以向孩子发送一个信号,表明它已经完成。

编辑:由于您使用fork而不是线程生成子进程,因此您不能在此处使用条件变量(父级和子级将具有单独的副本)。

相反,您可以使用signal()kill()函数在进程之间发送信号。在分叉之前,使用getpid来存储父pid的副本(用于子进程)。还存储fork的返回值,因为它将包含子项的pid。

要向其他进程发送信号,请使用以下内容:

kill(parent_pid, SIGUSR1);

接收过程需要设置信号处理程序。例如:

int signal_received = 0;
void signal_handler(int signal_num) {
    if (signal_num == SIGUSR1)
        signal_received = 1;
}

signal(SIGUSR1, signal_handler);

只要进程收到信号编号signal_handler,就会自动调用函数SIGUSR1。你的线程会在一个循环中等待,看着这个变量使用类似的东西来改变:

while (1) { // Signal processing loop
    // Wait here for a signal to come in
    while (!signal_received) { sleep(1); }

    // Wake up and do something
    read_from_pipe();
    ...
    signal_received = 0;
}