C IPC等待孩子
所以我有一个程序创建一个子进程并执行一个命令(例如ls)。父母然后将使用管道发送和从孩子获得。当我从命令行自己输入命令时,这工作正常。C IPC等待孩子
但是,当输入来自文件时,看起来孩子没有足够的时间运行,并且从管道读取时我得到NULL - 即使会有信息来自它。
使用睡眠()的缺点,有没有更好的方法来确保孩子在尝试读取它之前已经运行?
非常感谢!
如果没有设置你管文件描述符非阻塞的,那么就应该没有问题。任何对管道的读取都会阻塞,直到孩子产生输出;如果需要响应多个文件描述符(例如,来自用户的标准输入和来自子进程的管道),请使用select()
或poll()
。
我认为它是fgets()
返回NULL。这表示文件结束(意味着孩子已经关闭了管道的末端),或者是错误。您可以使用feof()
或ferror()
来检查其中哪些为真。在错误情况下使用perror()
来查看错误实际是什么。
问题是你对孩子有多少控制?如果你自己写孩子,那么你可以让孩子在共享内存中设置一个标志,它已经开始(或触摸一个文件或任何你喜欢的痒痒),然后只有当你知道孩子在线运行它。
如果您对孩子没有控制权,仍然可以通过用自己的脚本包装孩子来实现上述解决方案,该脚本首先启动孩子,然后设置共享内存,这可以采用一个shell脚本如下
#!/bin/sh
$CHILD
my_app_that_set_the_flag
最后另一种选择是继续等待aslong当你从管空,显然这会导致一个无限循环,但如果你不能garuntee,你总是会得到的东西管道
您的父线程需要等到孩子准备好再尝试重新广告来自管道。有几种方法可以做到这一点。
首先,您可以使用条件变量。声明两个线程都可以访问的变量并将其设置为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;
}
您可以简单地使用'select()'等待管道可读。 – caf 2010-04-29 23:53:06
@caf:是的,但只是告诉你有什么需要阅读的东西。 select()'告诉你,你可以并不意味着你所有的数据都在那里。许多时候,等待所有内容都准备好被读取比读取内容时更容易,然后尝试将它重新组合在一起(特别是如果数据本身不能告诉你在哪里结束是)。 – bta 2010-04-29 23:59:30
这似乎是最简单的解决方案,所以我尝试了它 - 但无法让它工作。这个变量是在我做了fork之后被声明的,并且在孩子中发生了变化,但是父母似乎根本没有看到变化。这可能与我在儿童中使用exec有关吗? – Gary 2010-04-30 01:51:51
应该提到文件描述符是非阻塞的。我这样做是因为当没有新数据时,从fgets()中读取数据被阻塞,导致程序永远等待。 – Gary 2010-04-30 00:15:26
@Gary:在这种情况下,使用'select()'将文件描述符添加到您正在监视的文件描述符集中 - 例如,如果您想等待来自用户或来自管道的输入,请使用'select )'来监视stdin和管道。 – caf 2010-04-30 00:20:39
在这种情况下,我只想从一个文件描述符输入而不是标准输入,所以我不认为我需要选择?基本上我只是想给孩子足够的时间来运行它的命令,如果它仍然是NULL,就把它当作错误来处理。 – Gary 2010-04-30 01:47:56