我遇到一些fork()和其他问题。
我正在开发一个shell,用户可以在其中编写可以像普通shell一样执行的命令。
我有一个这样的主要功能:
void Shell::init() {
string command;
while (1) {
cout << getPrompt() << " ";
command = readCommand();
if (command.length() > 0) handleCommand(command);
}
}
handleCommand()
是几乎可以完成所有事情的功能。在其中的某个地方,我有以下内容:
...
else {
pid_t pid;
pid = fork();
char* arg[tokens.size() + 1];
for (int i = 0; i < tokens.size(); ++i) {
arg[i] = (char*) tokens[i].c_str();
}
arg[tokens.size()] = NULL;
if (pid == 0) {
if (execvp(tokens[0].c_str(), arg) == -1) {
cout << "Command not known. " << endl;
};
} else {
wait();
}
}
我想要的是,当我达到这一点时,该命令将被视为程序调用,因此我创建了一个子程序来运行它。它的工作几乎完美,但我在程序输出之前再次得到提示。例如:
tronfi@orion:~/NetBeansProjects/Shell2$ whoami
tronfi@orion:~/NetBeansProjects/Shell2$ tronfi
tronfi@orion:~/NetBeansProjects/Shell2$
孩子应该在execvp
之后死亡,所以它不应该调用提示,并且父母正在等待孩子死亡。
那么......我做错了什么?
谢谢!
答案 0 :(得分:3)
我不确定这是不是问题,但即使execvp()
失败,您也必须确保孩子退出:
if (pid == 0) {
if (execvp(tokens[0].c_str(), arg) == -1) {
cout << "Command not known. " << endl;
};
exit(1); // or some other error code to indicate execvp() fails
} else {
wait();
}
如果你不这样做,那么如果excecvp()
失败,你最终会得到你的shell的两个实例,这可能不是你想要的。
答案 1 :(得分:3)
您正在正确呼叫wait()
。它期望传递一个指向int的指针,其中将存储子的退出状态:
int status;
wait(&status);
但是,您应该使用waitpid()
来检查您所追踪的特定孩子。如果waitpid()
被信号中断,你还需要循环:
int r;
do {
r = waitpid(pid, &status, 0);
} while (r < 0 && errno == EINTR);
答案 2 :(得分:0)
必须使用调用
exit(0)终止子进程(仅在成功时),因为这有助于清理内存并刷新缓冲区。子项返回的状态必须由父项检查,然后才能提示。
如果您需要更多详细信息,请告诉我们。