编程语言:C和C++混合代码
上下文:有程序“A”从 STDIN 获取用户输入并向 STDOUT 输出响应。'A' 的输入和输出不适合我的预期用户。不幸的是,直接编辑或增加“A”不是一种选择。
方法:我创建了程序'B',它派生一个子进程来启动'A'并使用管道来拦截和翻译输入/输出(即在通过管道发送到A的STDIN之前获取用户输入并进行调整,并反过来接收'的STDOUT A' 通过管道并为用户调整。)
问题:当尝试接收“A”的输出时,程序似乎在通信中“挂起”。我的研究使我相信这个问题可能是 3 个问题中的 1 个:*为清楚起见,让管道 1 是从父(B)发送到“A”的 STDIN 的数据,管道 2 用于从“的 STDOUT 发送数据” A'给父母。
- 与管道 2 关联的流末尾没有 EOF。这方面的一个指示性症状是管道 1 按预期运行,并且不受类似问题的影响,可能是因为程序“A”用于
cin
处理输入并查找“\ n'不是EOF。我尝试调整我的程序以逐行读取,但是在执行“A”的第一行之后(除了子进程打印的自我声明行)它停止接收数据。 - 当子级在尝试读取管道的同时,子级正在写入管道时,存在某种争用。
fgetc()
可能不会“消耗”管道 2 流缓冲区中的数据,因此子进程会阻塞,直到“接收到”该数据。这可能是问题所在,因为外壳/操作系统(STDIN)完美地接收了“A”(管道 1 数据)的输入,并且在那里缓冲处理得更好/不同,而 STDOUT 接收“A”的输出和将其传递给管道 2,因此所有缓冲责任都落在管道机制上。
下面是程序 B(“test.cpp”)的代码和我用于测试而不是 A(“test2.cpp”)的虚拟模拟程序。
测试.cpp
#include <cstdlib>
#include <cstdio>
#include <iostream>
#include <string>
#include <cstring>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
using namespace std;
int main()
{
pid_t pid;
int wpipe[2];//write to child pipe
int rpipe[2];//read from child pipe
//initiate pipes here
if(pipe(wpipe))
{
cout << "write pipe creation failed"<<endl;
return 1;
}
if(pipe(rpipe))
{
cout << "read pipe creation failed"<<endl;
return 1;
}
//fork child here
pid_t procID = vfork();//does not copy address space. better than fork?
if(procID==0)
{//child
//close unused pipe ends
close(wpipe[1]);//read from wpipe
close(rpipe[0]);//write to rpipe
//handle stdin & stdout pipes
dup2(wpipe[0],STDIN_FILENO);//reroute stdin to wpipe[0]
dup2(rpipe[1],STDOUT_FILENO);//reroute stdout to rpipe[1]
//close pipes since they are copied??
close(wpipe[0]);
close(rpipe[1]);
//prepare array for execv
char** args;
args = new char*[2];
args[0] = new char[8];
strcpy(args[0],"test2");
args[1] = (char*)0;
cout << "I'm child. Relinquishing procID & memory image to test 2."<<endl;
int test = execv(args[0],args);
if(test==-1)
cout << "Error: execv failed."<<endl;
delete[] args[0];
delete[] args;
exit(0);
}else if(procID>0)
{//parent
int state,c;
//close unused pipe ends
close(wpipe[0]);//write to wpipe
close(rpipe[1]);//read from rpipe
//communicate with child
FILE *wstream;
wstream = fdopen(wpipe[1],"w");
FILE *rstream;
rstream = fdopen(rpipe[0],"r");
//read from child
c = fgetc(rstream);
while(c!=EOF)
{
putchar(c);
c = fgetc(rstream);
}
fprintf(wstream,"test1\n");
c = fgetc(rstream);
while(c!=EOF)
{
putchar(c);
c = fgetc(rstream);
}
fprintf(wstream,"test2\n");
c = fgetc(rstream);
while(c!=EOF)
{
putchar(c);
c = fgetc(rstream);
}
fclose(wstream);
fclose(rstream);
waitpid(procID,&state,0);
cout << "I'm parent."<<endl;
}
else
{//failure to fork
cout << "Fork failed" << endl;
return 1;
}
return 0;
}
测试2.cpp
#include <iostream>
#include <string>
using namespace std;
int main()
{
string tmp = "";
cout << "started" << endl;
while(tmp=="")
cin >> tmp;
cout << tmp << endl;
tmp="";
while(tmp=="")
cin >> tmp;
cin >> tmp;
cout << tmp << endl;
cout << "exiting" << endl;
return 0;
}
对于冗长的问题和单一的代码,我提前道歉。