我正在编写一个模拟shell,我正在使用dup2编写管道编码。这是我的代码:
bool Pipe::execute() {
int fds[2]; //will hold file descriptors
pipe(fds);
int status;
int errorno;
pid_t child;
child = fork();
if (-1 == child) {
perror("fork failed");
}
if (child == 0) {
dup2(fds[1], STDOUT_FILENO);
close(fds[0]);
close(fds[1]);
this->component->lchild->execute();
_exit(1);
}
else if (child > 0) {
dup2(fds[0], STDIN_FILENO);
close(fds[0]);
close(fds[1]);
this->component->rchild->execute();
waitpid(child, &status, 0);
if ( WIFEXITED(status) ) {
//printf("child exited with = %d\n",WEXITSTATUS(status));
if ( WEXITSTATUS(status) == 0) {
cout << "pipe parent finishing" << endl;
return true;
}
}
return false;
}
}
this->component->lchild->execute();
和this->component->rchild->execute();
在相应的命令上运行execvp
。我已经确认每个都通过在父进程中打印出一个语句来返回。然而,在我的Pipe::execute()
中,似乎子进程没有完成,因为父进程中的cout语句从未打印,并且在初始化提示符($
)后出现分段错误(参见图片)。这是在每次执行后初始化提示符的main函数:
int main()
{
Prompt new_prompt;
while(1) {
new_prompt.initialize();
}
return 0;
}
这是initialize()
功能:
void Prompt::initialize()
{
cout << "$ ";
std::getline(std::cin, input);
parse(input);
run();
input.clear();
tokens.clear();
fflush(stdout);
fflush(stdin);
return;
}
似乎ls | sort
运行正常,但是当初始化提示时,getline将读入空行。我尝试过使用cin.clear(),cin.ignore和上面的fflush和clear()行。该空白字符串被“解析”,然后调用run()
函数,该函数尝试取消引用空指针。关于为什么/这个空白行被输入getline的任何想法?我该如何解决这个问题?谢谢!
更新:管道中的父进程现在正在完成。我也注意到我的I / O重定向类(>
和<
)也遇到了seg错误。我想我不是正在刷新流或正确关闭文件描述符...
这是我的孩子和孩子的qazxsw poi功能:
execute()
这是错误:
bool Command::execute() {
int status;
int errorno;
pid_t child;
vector<char *> argv;
for (unsigned i=0; i < this->command.size(); ++i) {
char * cstr = const_cast<char*>(this->command.at(i).c_str());
argv.push_back(cstr);
}
argv.push_back(NULL);
child = fork();
if (-1 == child) {
perror("fork failed");
}
if (child == 0) {
errorno = execvp(*argv.data(), argv.data());
_exit(1);
} else if (child > 0) {
waitpid(child, &status, 0);
if ( WIFEXITED(status) ) {
//printf("child exited with = %d\n",WEXITSTATUS(status));
if ( WEXITSTATUS(status) == 0) {
//cout << "command parent finishing" << endl;
return true;
}
}
return false;
}
}
你正在为父母关闭stdin,而不仅仅是正确的孩子。在此之后,父进程的stdin与正确子进程的stdin相同。
之后
else if (child > 0) {
dup2(fds[0], STDIN_FILENO);
close(fds[0]);
close(fds[1]);
this->component->rchild->execute();
试图读取左子的输出,而不是原始的stdin。到那时,左边的孩子已经完成,管道的一端已经关闭。这使得读取stdin失败,并使std::getline(std::cin, input);
保持原始状态不变。
编辑:您的设计有一个小问题和一个主要缺陷。小缺陷是你不需要在input
的叉子。主要缺陷是孩子应该是重定向流并关闭描述符的人。
只需通过fork()传递输入和输出参数,然后让孩子们使用dup2。不要忘记使它也关闭不相关的管端。如果不这样做,左边的孩子将完成,但其输出管道将继续生活在其他过程中。只要该描述符的其他副本存在,那么正确的孩子在阅读其管道末端时永远不会获得EOF - 并且永远不会有周块。