我正在用C++实现一个类似于shell的程序。它有一个循环,从cin读取数据,然后fork出子进程并等待其返回结果。
如果输入是交互式的或者从另一个程序进行了管道传输,那么这个程序可以正常运行。但是,当输入是一个bash heredoc时,程序会重新读取部分输入(有时无限期地重复读取)。
我知道子进程会继承父进程的文件描述符,包括共享文件偏移量。但是,这个例子中的子进程没有从cin读取任何内容,所以我认为它不应该接触偏移量。我对这种情况感到困惑。
test.cpp:
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
int main(int argc, char **argv)
{
std::string line;
while (std::getline(std::cin, line)) {
pid_t pid = fork();
if (pid == 0) { // child
break; // exit immediately
}
else if (pid > 0) { // parent
waitpid(pid, nullptr, 0);
}
else { // error
perror("fork");
}
std::cout << getpid() << ": " << line << "\n";
}
return 0;
}
我按照以下方式编译:
g++ test.cpp -std=c++11
然后我用以下命令运行它:
./a.out <<EOF
hello world
goodbye world
EOF
输出:
7754: hello world
7754: goodbye world
7754: goodbye world
如果我在输入命令中添加第三行foo bar
,程序就会陷入无限循环:
13080: hello world
13080: goodbye world
13080: foo bar
13080: o world
13080: goodbye world
13080: foo bar
13080: o world
[...]
版本信息:
- Linux内核: 4.4.0-51-generic
- Ubuntu系统: 16.04.1 LTS (xenial)
- Bash shell: GNU bash, version 4.3.46(1)-release (x86_64-pc-linux-gnu)
- GCC编译器: g++ (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609
std::ios::sync_with_stdio(false);
并在写入 stdout 后显式刷新会发生什么?(例如将'\n'
更改为std::endl
) - user1084944exit(0)
但不会在_exit(0)
时发生。 - Sam Varshavchikexec
函数,你绝对应该在 fork 出的子进程中使用_exit
或quick_exit
函数。父进程会构建cout
缓冲区状态并且子进程会继承它。如果子进程正常退出,他们将尝试刷新自己拷贝的cout
缓冲区,而此时父进程正在刷新缓冲区。如果发生这种情况,你将在输出中获得重复项。 - Petr Skocik