如何停止执行第一个子进程?

时间:2018-08-17 10:57:29

标签: c++ fork

目标:设计一个Linux外壳程序,其中显示提示用户输入信息,创建一个新进程来执行该命令,然后终止/退出该进程。这是我的代码

#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>

using namespace std;

string cmd; //global string so cmd copied to child to execute    

void HandleAsParent(){
    cout<<"Linux Shell 1.0\n";
    string s;
    while (!exitflag) {
        cout<<"myShell>";
        getline(cin,cmd); //Take user input
        fork();
        wait(NULL);
    }
}

void HandleAsChild(){
    cout<<"Executing";
    system(cmd.c_str());
}

int main() {
    pid_t p = fork();
    if(p != 0){
        HandleAsParent(); //This is parent process
    }
    else {
        HandleAsChild(); //This is child process
    }
}

问题在于,由于主程序中的第一个fork()调用,

  

myShell>执行

在程序运行时显示在第一行,而不仅仅是

  

myShell>

。 我能够理解为什么会发生这种情况,但无法弄清楚如何停止执行第一个子进程。 请为我提出解决问题的方法/解决方案。

  

编辑1:这是我的作业之一(用于学习UNIX进程)   问题,并且明确指出该程序“会提示   用户使用命令,解析该命令,然后使用   子进程“

1 个答案:

答案 0 :(得分:2)

正如我已经猜到的,system()可能使用fork()exec()wait()的组合。出于好奇,我搜索了源代码,并在woboq.org上找到了一个:glibc/sysdeps/posix/system.c

请记住,使用system(),所需的子进程“免费提供”。所以,我得到了这个最小的样本:

#include <iostream>

void callCmd(const std::string &cmd)
{
  system(cmd.c_str());
}

int main()
{
  std::cout << "My Linux Shell 1.0\n"
    << "Type exit[Enter] to exit.\n";
  for (;;) {
    std::cout << "> ";
    std::string input; std::getline(std::cin, input);
    if (input == "exit") return 0;
    callCmd(input);
  }
}

已在Windows 10的cygwin上进行了编译和测试:

$ g++ -std=c++11 -o mycroShell mycroShell.cc 

$ ./mycroShell 
My Linux Shell 1.0
Type exit[Enter] to exit.
> echo "Hello"
Hello
> exit

$

运行此命令后,system()中的callCmd()调用可以替换为fork() / exec() / wait(),而无需更改其他任何内容。


简化版可能如下所示:

#include <iostream>
#include <string>
#include <vector>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

void callCmd(const std::string &input)
{
  // the pre-processing: split the input into command and arguments
  std::string cmdArgs = input;
  std::vector<char*> args;
  char *cmd = &cmdArgs[0];
  args.push_back(cmd);
  for (char *c = cmd; *c; ++c) {
    if (*c == ' ') {
      *c = '\0'; args.push_back(c + 1);
    }
  }
  args.push_back(nullptr); // append terminator
  // simple replacement of system() (not that sophisticated)
  int ret = fork();
  if (ret < 0) { // failure
    std::cerr << "Failed to execute '" << cmd << "'!\n";
  } else if (ret == 0) { // child
    execvp(cmd, args.data());
  } else { // parent
    waitpid(ret, nullptr, 0);
  }
}

int main()
{
  std::cout << "My Linux Shell 1.1\n"
    << "Type exit[Enter] to exit.\n";
  for (;;) {
    std::cout << "> ";
    std::string input; std::getline(std::cin, input);
    if (input == "exit") return 0;
    callCmd(input);
  }
}

再次在Windows 10的cygwin上进行编译和测试:

$ g++ -std=c++11 -o mycroShell mycroShell.cc 

$ ./mycroShell
My Linux Shell 1.1
Type exit[Enter] to exit.
> /usr/bin/echo "Hello"
"Hello"
> exit

$

注意:

  1. 恕我直言,最棘手的部分是为execvp准备适当的参数向量。

  2. 我也尝试了echo "Hello",它也有效。 echo是bash内置命令,这让我有些惊讶。我假设它找到了/usr/bin/echo并在上面的输出中使用了它。

  3. 错误处理能力很差-对于严重的应用程序应该进行扩展。