fork和exec有什么区别?


当前回答

fork()和exec()的主要区别是:

fork()系统调用创建当前运行程序的克隆。在fork()函数调用之后,原程序继续执行下一行代码。克隆也会在下一行代码处开始执行。 看看下面的代码,我从http://timmurphy.org/2014/04/26/using-fork-in-cc-a-minimum-working-example/

#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv)
{
    printf("--beginning of program\n");
    int counter = 0;
    pid_t pid = fork();
    if (pid == 0)
    {
        // child process
        int i = 0;
        for (; i < 5; ++i)
        {
            printf("child process: counter=%d\n", ++counter);
        }
    }
    else if (pid > 0)
    {
        // parent process
        int j = 0;
        for (; j < 5; ++j)
        {
            printf("parent process: counter=%d\n", ++counter);
        }
    }
    else
    {
        // fork failed
        printf("fork() failed!\n");
        return 1;
    }
    printf("--end of program--\n");
    return 0;
}

这个程序在fork()之前声明了一个计数器变量,设为0。在fork调用之后,我们有两个并行运行的进程,它们都增加了自己版本的计数器。每个进程将运行到完成并退出。因为这些进程是并行运行的,所以我们无法知道哪个进程会先完成。运行此程序将输出类似于下面所示的内容,尽管每次运行的结果可能不同。

--beginning of program
parent process: counter=1
parent process: counter=2
parent process: counter=3
child process: counter=1
parent process: counter=4
child process: counter=2
parent process: counter=5
child process: counter=3
--end of program--
child process: counter=4
child process: counter=5
--end of program--

exec()系统调用族用另一段代码替换进程当前执行的代码。进程保留了它的PID,但它变成了一个新的程序。例如,考虑以下代码:

#include <stdio.h> 
#include <unistd.h> 
main() {
 char program[80],*args[3];
 int i; 
printf("Ready to exec()...\n"); 
strcpy(program,"date"); 
args[0]="date"; 
args[1]="-u"; 
args[2]=NULL; 
i=execvp(program,args); 
printf("i=%d ... did it work?\n",i); 
} 

该程序调用execvp()函数将其代码替换为date程序。如果代码存储在名为exec1.c的文件中,则执行它会产生以下输出:

Ready to exec()... 
Tue Jul 15 20:17:53 UTC 2008 

程序输出一行-Ready to exec()…‖并且在调用execvp()函数后,将其代码替换为date程序。注意这一行-…它是否工作‖不显示,因为在这一点上,代码已被替换。相反,我们看到执行-date -u.‖的输出

其他回答

Fork()将当前进程拆分为两个进程。换句话说,你的线性程序突然变成了两个单独的程序,运行着一段代码:

 int pid = fork();

 if (pid == 0)
 {
     printf("I'm the child");
 }
 else
 {
     printf("I'm the parent, my child is %i", pid);
     // here we can kill the child, but that's not very parently of us
 }

这可能会让你大吃一惊。现在,两个进程执行了一段状态几乎相同的代码。子进程继承刚刚创建它的进程的所有代码和内存,包括从fork()调用刚刚停止的地方开始。唯一的区别是fork()返回的代码告诉你你是父类还是子类。如果你是父进程,返回值是子进程的id。

Exec更容易掌握一些,您只需告诉Exec使用目标可执行文件执行一个进程,并且不需要两个进程运行相同的代码或继承相同的状态。就像@Steve Hawkins说的,exec可以在你fork后在当前进程中执行目标可执行文件。

fork ():

它创建正在运行的进程的副本。正在运行的进程称为父进程,新创建的进程称为子进程。区分两者的方法是通过查看返回值:

Fork()返回父进程中子进程的标识符(pid) Fork()在子对象中返回0。

exec ():

它在一个流程中启动一个新流程。它将一个新程序加载到当前进程中,替换现有的程序。

Fork () + exec():

当启动一个新程序时,首先fork(),创建一个新进程,然后exec()(即加载到内存并执行)它应该运行的程序二进制。

int main( void ) 
{
    int pid = fork();
    if ( pid == 0 ) 
    {
        execvp( "find", argv );
    }

    //Put the parent to sleep for 2 sec,let the child finished executing 
    wait( 2 );

    return 0;
}

Fork()创建当前进程的副本,在Fork()调用之后的新子进程中执行。在fork()之后,除了fork()函数的返回值外,它们是相同的。(详情请参阅RTFM。)这两个进程可以进一步分离,其中一个进程不能干扰另一个进程,除非可能通过任何共享的文件句柄。

Exec()将当前进程替换为新进程。它与fork()无关,只是当需要启动不同的子进程,而不是替换当前进程时,exec()通常会在fork()之后执行。

理解fork()和exec()概念的主要例子是shell,用户通常在登录到系统后执行命令解释器程序。shell将命令行的第一个单词解释为命令名

对于许多命令,shell fork和子进程执行与名称相关的命令,将命令行上的剩余单词作为命令的参数。

shell允许三种类型的命令。首先,命令可以是 包含由源代码编译产生的目标代码的可执行文件(例如C程序)。其次,命令可以是一个可执行文件 包含shell命令行序列。最后,命令可以是一个内部shell命令。(而不是一个可执行文件ex->cd,ls等)

fork()和exec()的主要区别是:

fork()系统调用创建当前运行程序的克隆。在fork()函数调用之后,原程序继续执行下一行代码。克隆也会在下一行代码处开始执行。 看看下面的代码,我从http://timmurphy.org/2014/04/26/using-fork-in-cc-a-minimum-working-example/

#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv)
{
    printf("--beginning of program\n");
    int counter = 0;
    pid_t pid = fork();
    if (pid == 0)
    {
        // child process
        int i = 0;
        for (; i < 5; ++i)
        {
            printf("child process: counter=%d\n", ++counter);
        }
    }
    else if (pid > 0)
    {
        // parent process
        int j = 0;
        for (; j < 5; ++j)
        {
            printf("parent process: counter=%d\n", ++counter);
        }
    }
    else
    {
        // fork failed
        printf("fork() failed!\n");
        return 1;
    }
    printf("--end of program--\n");
    return 0;
}

这个程序在fork()之前声明了一个计数器变量,设为0。在fork调用之后,我们有两个并行运行的进程,它们都增加了自己版本的计数器。每个进程将运行到完成并退出。因为这些进程是并行运行的,所以我们无法知道哪个进程会先完成。运行此程序将输出类似于下面所示的内容,尽管每次运行的结果可能不同。

--beginning of program
parent process: counter=1
parent process: counter=2
parent process: counter=3
child process: counter=1
parent process: counter=4
child process: counter=2
parent process: counter=5
child process: counter=3
--end of program--
child process: counter=4
child process: counter=5
--end of program--

exec()系统调用族用另一段代码替换进程当前执行的代码。进程保留了它的PID,但它变成了一个新的程序。例如,考虑以下代码:

#include <stdio.h> 
#include <unistd.h> 
main() {
 char program[80],*args[3];
 int i; 
printf("Ready to exec()...\n"); 
strcpy(program,"date"); 
args[0]="date"; 
args[1]="-u"; 
args[2]=NULL; 
i=execvp(program,args); 
printf("i=%d ... did it work?\n",i); 
} 

该程序调用execvp()函数将其代码替换为date程序。如果代码存储在名为exec1.c的文件中,则执行它会产生以下输出:

Ready to exec()... 
Tue Jul 15 20:17:53 UTC 2008 

程序输出一行-Ready to exec()…‖并且在调用execvp()函数后,将其代码替换为date程序。注意这一行-…它是否工作‖不显示,因为在这一点上,代码已被替换。相反,我们看到执行-date -u.‖的输出