C.等待儿童

C.等待儿童,c,ipc,C,Ipc,所以我有一个程序,它创建一个子进程并执行一个命令(例如,ls)。然后,父级将使用管道向子级发送和从子级获取。当我自己从命令行输入命令时,这工作正常 然而,当输入来自一个文件时,似乎孩子没有足够的时间运行,并且我在从管道中读取时会得到NULL,即使会有来自它的信息 除了使用sleep(),还有更好的方法确保孩子在阅读之前已经跑了吗 非常感谢 问题是你对孩子有多大的控制权?如果您自己编写孩子,那么您可以让孩子在共享内存中设置一个标志,表明它已启动(或触摸文件或任何您喜欢的内容),然后只有在您知道孩子

所以我有一个程序,它创建一个子进程并执行一个命令(例如,ls)。然后,父级将使用管道向子级发送和从子级获取。当我自己从命令行输入命令时,这工作正常

然而,当输入来自一个文件时,似乎孩子没有足够的时间运行,并且我在从管道中读取时会得到NULL,即使会有来自它的信息

除了使用sleep(),还有更好的方法确保孩子在阅读之前已经跑了吗


非常感谢

问题是你对孩子有多大的控制权?如果您自己编写孩子,那么您可以让孩子在共享内存中设置一个标志,表明它已启动(或触摸文件或任何您喜欢的内容),然后只有在您知道孩子在线后才能运行它

如果您无法控制子系统,那么仍然需要通过使用自己的脚本包装子系统来实现上述解决方案,该脚本首先启动子系统,然后设置共享内存,可以采用shell脚本的形式,如下所示

#!/bin/sh

$CHILD
my_app_that_set_the_flag

最后,另一种选择是,只要从管道中获取NULL,就继续等待,这显然会导致一个无限循环,但如果您不能保证总是在管道中获取某些内容,那么问题是您对孩子有多大的控制权?如果您自己编写孩子,那么您可以让孩子在共享内存中设置一个标志,表明它已启动(或触摸文件或任何您喜欢的内容),然后只有在您知道孩子在线后才能运行它

如果您无法控制子系统,那么仍然需要通过使用自己的脚本包装子系统来实现上述解决方案,该脚本首先启动子系统,然后设置共享内存,可以采用shell脚本的形式,如下所示

#!/bin/sh

$CHILD
my_app_that_set_the_flag

最后,另一种选择是,只要从管道中获取NULL,就继续等待,这显然会导致无限循环,但如果不能保证总是在管道中获取某些内容,则父线程需要等待直到子线程准备就绪,然后再尝试从管道中读取。有几种方法可以做到这一点

首先,可以使用条件变量。声明一个两个线程都可以访问的变量,并将其设置为
0
。当准备好让父线程读取时,子线程将其设置为
1
。父级将等待变量更改为
1
(使用类似
的方法,而(!condvar)sleep(1);
),然后它将从管道中读取并将变量重置为
0
,以便子级知道父级已完成

另一种选择是使用进程间通信的形式,例如。与条件变量方法类似,子线程将执行其工作,然后在完成时向父线程发送信号。父线程将等待收到信号后再从管道中读取,然后它可以向子线程发送一个信号,指示该操作已完成

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

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

要向另一个进程发送信号,请使用以下命令:

kill(parent_pid, 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;
}
接收过程需要设置一个信号处理程序。例如:

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

signal(SIGUSR1, signal_handler);
每当进程接收到信号编号
SIGUSR1
时,就会自动调用函数
signal\u handler
。您的线程将在一个循环中等待,并使用如下方式监视此变量的更改:

kill(parent_pid, 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;
}

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

首先,可以使用条件变量。声明一个两个线程都可以访问的变量,并将其设置为
0
。当准备好让父线程读取时,子线程将其设置为
1
。父级将等待变量更改为
1
(使用类似
的方法,而(!condvar)sleep(1);
),然后它将从管道中读取并将变量重置为
0
,以便子级知道父级已完成

另一种选择是使用进程间通信的形式,例如。与条件变量方法类似,子线程将执行其工作,然后在完成时向父线程发送信号。父线程将等待收到信号后再从管道中读取,然后它可以向子线程发送一个信号,指示该操作已完成

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

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

要向另一个进程发送信号,请使用以下命令:

kill(parent_pid, 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;
}
接收过程需要设置一个信号处理程序。例如:

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

signal(SIGUSR1, signal_handler);
每当进程接收到信号编号
SIGUSR1
时,就会自动调用函数
signal\u handler
。您的线程将在一个循环中等待,并使用如下方式监视此变量的更改:

kill(parent_pid, 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;
}

如果您没有将管道文件描述符设置为非阻塞,那么应该没有问题。有人读过吗