简体   繁体   English

C IPC等待孩子

[英]C IPC waiting for child

So I have a program which creates a child process and executes a command (for example, ls). 所以我有一个程序,它创建一个子进程并执行一个命令(例如,ls)。 The parent will then use pipes to send to and get from the child. 然后,父母将使用管道发送给孩子并从孩子那里取得。 This works fine when I'm inputting commands myself from the command line. 当我从命令行输入命令时,这很好用。

However, when the input comes from a file, it seems like the child doesn't have enough time to run and I get NULL when reading from the pipe - even though there will be information coming from it. 但是,当输入来自文件时,似乎孩子没有足够的时间来运行,并且从管道读取时我得到NULL - 即使会有来自它的信息。

Short of using sleep(), is there a better way to make sure the child has run before trying to read from it? 没有使用sleep(),有没有更好的方法来确保孩子在尝试阅读之前已经运行了?

Thanks a lot! 非常感谢!

If your haven't set your pipe file descriptor as non-blocking, then there should be no problem. 如果您没有将管道文件描述符设置为非阻塞,那么应该没有问题。 Any read on the pipe will block until the child produces output; 管道上的任何读数都会阻塞,直到孩子产生输出; if you need to be responsive to multiple file descriptors (for example, standard input from the user and the pipe from the child process), use select() or poll() . 如果您需要响应多个文件描述符(例如,来自用户的标准输入和来自子进程的管道),请使用select()poll()

I assume it is fgets() that is returning NULL. 我假设fgets()返回NULL。 That indicates either end-of-file (meaning that the child has closed its end of the pipe), or an error. 这表示文件结束(意味着孩子已关闭管道的末尾)或错误。 You can check which of these is true using feof() or ferror() . 你可以使用feof()ferror()来检查其中哪一个是真的。 Use perror() in the error case to see what the error actually is. 在错误情况下使用perror()来查看错误实际是什么。

The question is how much control do you have on the child? 问题是你对孩子有多少控制? If you are writing the child yourself then you can get the child to set a flag in shared memory that it has started (or touch a file or whatever tickles your fancy) and then only once you know the child is online run it. 如果您自己编写孩子,那么您可以让孩子在已启动的共享内存中设置一个标志(或触摸文件或您想要的任何痒痒),然后只有在您知道孩子在线运行它之后。

If you don't have control over the child, there is still away to implement the above solution by wrapping the child with your own script which first launches the child then sets the shared memory, This could be in the form of a shell script as follows 如果您无法控制子进程,那么仍然可以通过使用您自己的脚本包装子进程来实现上述解决方案,该脚本首先启动子进程然后设置共享内存。这可以是shell脚本的形式,如如下

#!/bin/sh

$CHILD
my_app_that_set_the_flag

Finally another alternative is to continue waiting aslong as you get NULL from the pipe, obviously this would lead to an infinite loop though if you can not garuntee that you will always get something on the pipe 最后另一个选择是继续等待从管道中获取NULL,显然这会导致无限循环,但如果你不能指望你总会在管道上得到一些东西

Your parent thread needs to wait until the child is ready before it tries to read from the pipe. 您的父线程需要等到子项准备好后再尝试从管道读取。 There are a couple of ways to do this. 有几种方法可以做到这一点。

First, you can use a condition variable. 首先,您可以使用条件变量。 Declare a variable that both threads can access and set it to 0 . 声明两个线程都可以访问的变量并将其设置为0 Your child thread will set it to 1 when is is ready for the parent to read. 当父级已准备好阅读时,您的子线程将其设置为1 The parent will wait until the variable changes to 1 (using something like while(!condvar) sleep(1); ), then it will read from the pipe and reset the variable to 0 so that the child knows that the parent is finished. 父将等到变量变为1 (使用while(!condvar) sleep(1); ),然后它将从管道中读取并将变量重置为0以便子项知道父项已完成。

Another option is to use a form of inter-process communication, such as signals . 另一种选择是使用一种进程间通信形式,例如信号 Similar to the condition variable method, the child thread will perform its work and then send a signal to the parent thread when it is done. 与条件变量方法类似,子线程将执行其工作,然后在完成时向父线程发送信号。 The parent thread will wait until it receives the signal before it reads from the pipe, and then it can send a signal back to the child indicating that it is done. 父线程将一直等到它从管道读取之前接收到信号,然后它可以向子节点发送一个信号,指示它已完成。

Edit: Since you're spawning the child process with fork instead of with threads, you can't use a condition variable here (parent and child will have separate copies of it). 编辑:由于您使用fork而不是使用线程生成子进程,因此您不能在此处使用条件变量(父级和子级将具有单独的副本)。

Instead, you can use the signal() and kill() functions to send signals between the processes. 相反,您可以使用signal()kill()函数在进程之间发送信号。 Before forking, use getpid to store a copy of the parent's pid (for the child process). 在分叉之前,使用getpid存储父pid的副本(用于子进程)。 Also store the return value of fork , since it will contain the child's pid. 还存储fork的返回值,因为它将包含子的pid。

To send a signal to the other process, use something like: 要向其他进程发送信号,请使用以下内容:

kill(parent_pid, SIGUSR1);

The receiving process needs to set up a signal handler. 接收过程需要设置信号处理程序。 For example: 例如:

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

signal(SIGUSR1, signal_handler);

The function signal_handler now will be automatically called whenever the process receives signal number SIGUSR1 . 现在,只要进程收到信号编号SIGUSR1就会自动调用signal_handler函数。 Your thread would wait in a loop, watching for this variable to change using something like: 你的线程会在一个循环中等待,看着这个变量改变使用类似的东西:

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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM