我的任务有问题。
在父进程死后,我必须在子进程中从终端读取数据。很明显,父进程必须在执行子进程后立即死亡,因此我找到的解决方案(例如使用wait()
)对我来说无用。
我的代码
int main(void)
{
printf("start main\n");
if(fork() == 0){
char buffer[64];
fgets(buffer, 64, stdin);
printf("Child process: %s\n", buffer);
}
else printf("end main\n");
//Using WAIT() here is not allowed in my assignment.
return 0;
}
它不等我输入数据。似乎在父结束后,子进程在后台并且它无法从终端读取任何数据。
结果
damian@damian-Virtualbox:-$ ./testuje
start main
end main
damian@damian-Virtualbox:-$ Child Process:
echo test | ./testuje
start main
end
damian@damian-Virtualbox:-$ Child Process: test
应该做什么计划
print: start main
print: end main
then it should:
wait for user to type something
print: child process: text_typed_by_user
编辑:我被建议使用tee
命令。你知道怎么用它来实现我想要的吗?
答案 0 :(得分:2)
您可能希望使用vfork
代替fork
(请检查documentation here):
pid_t vfork(void);
vfork - create a child process and block parent
答案 1 :(得分:1)
使用wait
不是一个选项,因为父进程可以使用它来监视子进程的退出状态。
将子进程与父进程事件同步的一种可能方法是使用在进程终止时关闭所有打开的文件描述符的事实。因此,可以使用socketpair
打开一对连接的套接字来通知已退出的父项。默认情况下,socketpair将创建阻塞套接字,当父进程退出并且sp[0]
关闭时,它将通知子进程中的sp[1]
,read
将返回0.未经测试的代码如下:
int sp[2];
socketpair(AF_UNIX,SOCK_STREAM,0,sp); // needs error check
switch (fork()) {
case -1: // error
break;
case 0: // parent
close(sp[1]);
....
exit; // will close sp[0] too
default: // child
close(sp[0]);
read(sp[1],sp,sizeof(int)); // needs error check
// here sp[0] was used as temp buffer
... // do your read
}
编辑:还有一种方法,但它只是看起来更简单,而不是更好,因为它使用CPU旋转,直到父退出(假设这对练习是可行的)。这可能会导致竞争条件:
// in child
pid_t ppid=getppid();
while (ppid==getppid()); // loop until parent dies
如果父母在第一次拨打getppid
之前退出,可能会发生竞赛。
此种族可以通过保存父进程pid
来修复,同时仍然在父级中,并且只在子级中循环:
// in parent, before fork
pid_t ppid=getpid();
....
// in child after fork
while (ppid==getppid()); // loop until parent dies
答案 2 :(得分:0)
你必须在fork之后调用子进程中的setsid()
。当父节点终止时,这将阻止对子节点的SIGHUP。
if(fork() == 0){
setsid();
char buffer[64];
fgets(buffer, 64, stdin);
printf("Child process: %s\n", buffer);
exit(EXIT_SUCCESS);
}
但是,主线程退出和setsid() - 调用之间可能存在竞争条件,您可能需要处理这种情况(丑陋但简单的黑客在fork之后的父级中是睡眠(1)( ))。
答案 3 :(得分:0)
您可以使用setsid
(与子进程创建新会话)与__fpurge
一起清除标准输入并避免垃圾fgets
输入:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdio_ext.h>
int main(void)
{
printf("start main\n");
if(fork() == 0){
char buffer[64];
setsid();
__fpurge(stdin);
fgets(buffer, 64, stdin);
printf("Child reads: '%s'\n", buffer);
}
else printf("end main\n");
return 0;
}
注意: fflush()
的POSIX标准表明stdin上的行为未定义。所以你应该避免fflush(stdin)
。 __fpurge
(在 stdio_ext.h 中定义)是this topic中提到的另一种选择。
答案 4 :(得分:0)
我已经实现了想要通过运行它来实现以下目标:
tee | ./myprogram
。