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

Posted

技术标签:

【中文标题】如何阻止第一个子进程被执行?【英文标题】:How to stop the first child process from being executed? 【发布时间】:2018-08-17 10:57:29 【问题描述】:

目标:要设计一个 linux shell,它会提示用户接受输入,创建一个新进程来执行该命令,然后终止/退出该进程。这是我的代码

#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
    

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

myShell>正在执行

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

我的壳>

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

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

【问题讨论】:

显示的代码中没有任何内容实际上需要fork()ing。你到底希望fork()ing 完成什么,然后在没有父进程等待的情况下在子进程中执行命令?只需摆脱无用的叉子。问题解决了。 这仍然是WIP,我卡在这里没有进一步编码,当然,父母会等待孩子完成然后再继续(显示提示) @SamVarshavchik 我已编辑添加一个 wait() 语句。 只需从 main 中移除 fork。它应该只包含int main() HandleAsParent(); return 0; 是的,这是我的作业(用于学习 UNIX 进程)问题之一,并且明确指出程序“提示用户输入命令,解析命令,然后执行它一个子进程“@Scheff 【参考方案1】:

正如我已经猜到的,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

$

运行此程序后,callCmd() 中的 system() 调用可以替换为 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

$

注意事项:

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

    我也尝试了echo "Hello",并且成功了。这让我有点惊讶,因为echo 是一个 bash 内置命令。我假设它找到了/usr/bin/echo 并在我上面的输出中使用了它。

    错误处理相当差——应该针对严重的应用程序进行扩展。

【讨论】:

OHMYGOD,fork 函数是从 fork 发生的地方开始还是从 main() 开始?? 正如我在(现已删除的)文本中所描述的那样。 fork() 返回父子进程。 IE。两个进程都在fork() 之后继续。 这就是为什么他们称它为fork()(就像用来吃饭的叉子一样)。 ;-)

以上是关于如何阻止第一个子进程被执行?的主要内容,如果未能解决你的问题,请参考以下文章

jquery如何获取第一个子元素

linux c之通过管道实现兄弟间进程通信:

如何在Docker容器中运行Nginx而不停止?

jquery如何获取第一个或最后一个子元素?

编写多进程编程

wireshark设置阻止进程上网