我正在尝试使用
pipe()
和 execlp()
从子进程获取字符串。为此创建函数后,我在主进程中使用了它两次,它第一次工作,但第二次不起作用。我想修复此代码以使其随时可用。
这是我的代码。
vector<string> getHelp2(string program_name){
string command = "man " + program_name;
int stdin_copy = dup(STDIN_FILENO);
int stdout_copy = dup(STDOUT_FILENO);
int stderr_copy = dup(STDERR_FILENO);
int pipefd[2] = {0, };
pipe(pipefd);
pid_t pid = fork();
if(pid == 0){
close(pipefd[0]);
dup2(pipefd[1], STDOUT_FILENO);
dup2(pipefd[1], STDERR_FILENO);
fcntl(pipefd[1], F_SETFD, FD_CLOEXEC);
execlp("man", "man", program_name.data() ,NULL);
}
else{
dup2(pipefd[0], STDIN_FILENO);
waitpid(pid, 0, 0);
close(pipefd[1]);
string str;
string substr;
getline(cin, substr);
getline(cin, substr);
while(getline(cin, substr)){
str+=substr+"\n";
}
dup2(stdin_copy, STDIN_FILENO);
dup2(stdout_copy, STDOUT_FILENO);
dup2(stderr_copy, STDERR_FILENO);
close(pipefd[0]);
cin.clear();
我恢复了
stdin
、stdout
、stderr
和 pipefd[2]
,甚至使用 fcntl
但它不起作用。我也用cin.clear()
。
添加:与标准输入不同,标准输出似乎没有恢复。怎样才能恢复呢?
如果 execlp 启动的程序产生了太多的数据,以至于在退出之前填满了管道并阻塞,则在等待父级从管道中排出一些数据的子级与等待子级退出的父级之间会出现死锁。对 waitpid 的调用。对 waitpid 的调用应该放在识别 pipelinefd[0] 上的文件结尾的点之后。
接下来,在 cin 基础设施下交换 STDIN_FILENO 引用的源可能会产生不确定的影响,特别是在一个关联与下一个关联之间检测到文件结尾的情况下。实际上,cin,尤其是其底层的 filebuf 实例,认为它已经到达文件末尾,然后您可以通过更改 STDIN_FILENO 引用的内容来移动目标位置。 clear 应该重置文件结束标志,但充其量这是不好的风格。会有两个很好的解决方案。一种是使用从文件描述符读取的 ifstream。请参阅如何从 POSIX 文件描述符构造 c++ fstream? 另一种方法是仅使用具有固定长度缓冲区的 Linux 读取函数。任何一种解决方案都可以消除所有文件描述符杂耍的需要。
我还注意到 stdin_copy、stdout_copy 和 stderr_copy 都没有关闭——无论是在父级还是子级中。尽管有必要将 pipelinefd[1] 复制到子级中的 STDIN_FILENO,但所有其他文件描述符杂耍都有点丑陋,并且可能容易出错,如上面所观察到的。