为什么外壳程序为每个命令创建一个新进程?

时间:2018-11-06 15:24:27

标签: c shell

我正在尝试使用C编程shell,我发现每个命令都在一个新进程中执行,我的问题是为什么我们要创建一个新进程来执行该命令?我们不能只在当前进程中执行命令吗?

3 个答案:

答案 0 :(得分:4)

这是由于UNIX系统的设计方式所致,exec系列调用替换了当前进程。因此,如果您希望Shell之后继续运行,则需要为exec调用创建一个新进程。

答案 1 :(得分:1)

执行命令时,发生以下情况之一:

  • 您正在执行内置命令
  • 您正在执行可执行程序

可执行程序需要完成许多工作:不同的内存部分(堆栈,堆,代码等),它以一组特定的特权执行,并且正在发生更多事情。

如果您在当前进程中运行此新的可执行程序,则将用新的程序替换当前程序(您的shell)。它工作得很好,但是当新的可执行程序完成后,您不能返回到您的shell,因为它不再在内存中了。这就是为什么我们创建一个新进程并在该新进程中运行可执行程序的原因。 Shell等待此新过程完成,然后收集其退出状态,并再次提示您执行新命令。

答案 2 :(得分:0)

  

我们不能仅在当前进程中执行命令吗?

当然可以,但是随后将用所调用命令的程序替换外壳程序。但这可能不是您在此特定应用程序中想要的东西。实际上,在许多情况下,通过execve替换过程程序是实现某些事情的最直接方法。但是,对于外壳,这可能不是您想要的。

您不应认为流程是要避免或“害怕”的事情。实际上,将不同的事物分为不同的过程是可靠性和安全性功能的基础。进程(大多数)是相互隔离的,因此,如果某个进程由于某种原因(错误,崩溃等)而终止,则在第一程度上这只会影响该特定进程。

可以尝试以下方法:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int segfault_crash()
{
    fprintf(stderr, "I will SIGSEGV...\n");
    fputs(NULL, stderr);
    return 0;
}

int main(int argc, char *argv)
{
    int status = -1;
    pid_t const forked_pid = fork();
    if( -1 == forked_pid ){
        perror("fork: ");
        return 1;
    }
    if( 0 == forked_pid ){
        return segfault_crash();
    }
    waitpid(forked_pid, &status, 0);
    if( WIFSIGNALED(status) ){
        fprintf(stderr, "Child process %lld terminated by signal %d\n",
            (long long)forked_pid,
            (int)WTERMSIG(status) );
    } else {
        fprintf(stderr, "Child process %lld terminated normally\n");
    }
    return 0;
}

这个小程序会派生自己,然后调用一个故意执行未定义行为的函数,该函数在普通系统上触发某种内存保护错误(Windows上的访问冲突分段错误)。但是,由于此崩溃已被隔离到专用进程中,因此父进程(以及同级进程)不会与其一起崩溃。

此外,进程可能会放弃其特权,将自身限制为仅系统调用的一部分,并被移至名称空间/容器中,每个名称空间/容器都可以防止进程中的错误破坏系统的其余部分。例如,现代浏览器就是通过这种方式来实现沙箱,以提高安全性。