📜  fork() 和 exec() 的区别

📅  最后修改于: 2021-09-13 02:01:41             🧑  作者: Mango

每个应用程序(程序)都是通过进程开始执行的,进程是程序的一个运行实例。进程是通过不同的系统调用创建的,最流行的是fork()exec()

叉()

pid_t pid = fork();

fork() 通过复制调用进程来创建一个新进程,新进程称为子进程,与称为父进程的调用进程完全相同,但以下情况除外:

  1. 子进程有自己唯一的进程 ID,并且此 PID 与任何现有进程组的 ID 都不匹配。
  2. 子进程的父进程 ID 与父进程 ID 相同。
  3. 子进程不会继承其父进程的内存锁和信号量调整。
  4. 子进程不会从其父进程继承未完成的异步 I/O 操作,也不会从其父进程继承任何异步 I/O 上下文。

fork() 的返回值
成功时,父进程返回子进程的PID,子进程返回0。失败时,在父进程中返回 -1,不创建子进程,并适当设置 errno。
fork 系统调用的详细文章

执行()

exec() 系列函数新的进程映像替换当前进程映像。它将程序加载到当前进程空间并从入口点运行它。

exec() 家族由以下函数组成,我在下面的 C 程序中实现了 execv() ,你可以试试休息作为练习

int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ..., 
                               char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[], 
                              char *const envp[]);

叉与执行

  • fork 启动一个新进程,它是调用它的进程的副本,而 exec 用另一个(不同的)进程替换当前进程映像。
  • 在 fork() 的情况下,父进程和子进程同时执行,而 Control 永远不会返回到原始程序,除非出现 exec() 错误。
// C program to illustrate  use of fork() &
// exec() system call for process creation
  
#include 
#include 
#include  
#include 
#include   
#include 
  
int main(){
   pid_t  pid;
   int ret = 1;
   int status;
   pid = fork();
  
   if (pid == -1){
  
      // pid == -1 means error occured
      printf("can't fork, error occured\n");
      exit(EXIT_FAILURE);
   }
   else if (pid == 0){
  
      // pid == 0 means child process created
      // getpid() returns process id of calling process
      // Here It will return process id of child process
      printf("child process, pid = %u\n",getpid());
      // Here It will return Parent of child Process means Parent process it self
      printf("parent of child process, pid = %u\n",getppid()); 
  
      // the argv list first argument should point to  
      // filename associated with file being executed
      // the array pointer must be terminated by NULL 
      // pointer
      char * argv_list[] = {"ls","-lart","/home",NULL};
  
      // the execv() only return if error occured.
      // The return value is -1
      execv("ls",argv_list);
      exit(0);
   }
   else{
      // a positive number is returned for the pid of
      // parent process
      // getppid() returns process id of parent of 
      // calling process
// Here It will return parent of parent process's ID
      printf("Parent Of parent process, pid = %u\n",getppid());
      printf("parent process, pid = %u\n",getpid()); 
  
        // the parent process calls waitpid() on the child
        // waitpid() system call suspends execution of 
        // calling process until a child specified by pid
        // argument has changed state
        // see wait() man page for all the flags or options
        // used here 
        if (waitpid(pid, &status, 0) > 0) {
              
            if (WIFEXITED(status) && !WEXITSTATUS(status)) 
              printf("program execution successful\n");
              
            else if (WIFEXITED(status) && WEXITSTATUS(status)) {
                if (WEXITSTATUS(status) == 127) {
  
                    // execv failed
                    printf("execv failed\n");
                }
                else 
                    printf("program terminated normally,"
                       " but returned a non-zero status\n");                
            }
            else 
               printf("program didn't terminate normally\n");            
        } 
        else {
           // waitpid() failed
           printf("waitpid() failed\n");
        }
      exit(0);
   }
   return 0;
}

输出:

parent process, pid = 11523
child process, pid = 14188
Program execution successful

参考 :
Linux 手册页

想要从精选的视频和练习题中学习,请查看 C 基础到高级C 基础课程。