码迷,mamicode.com
首页 > 系统相关 > 详细

Linux进程fork,exec,vfork详解

时间:2015-08-13 18:15:05      阅读:210      评论:0      收藏:0      [点我收藏+]

标签:linux   fork   exec   vfork   进程   

    在Unix/Linux系统下进程创建时需要进行如下系统调用:fork/exec

    fork()把一个进程复制成二个进程:parent (old PID), child (new PID)

    exec()用新程序来重写当前进程:PID没有改变

    接下来就重点学习这两个系统调用:

    当我们fork() 创建一个继承的子进程将会发生如下事情:复制父进程的所有变量和内存,复制父进程的所有CPU寄存器(有一个寄存器例外)(这个寄存器是用来区分父进程和子进程的PID)

    fork()的返回值:调用fork()函数成功时,将会有两个返回值。子进程的fork()返回0,父进程的fork()返回子进程标识符。fork() 返回值可方便后续使用,子进程可使用getpid()获取PID

    fork()执行过程对于子进程而言,是对父进程地址空间的一次复制。下面我们通过图示来看一下这个复制过程:

    技术分享

    注意了,图示中的两个childPID的值是不同的,对于父进程中的childPID当然是子进程的PID,而子进程中的childPID的值为0。

    fork()使用示例: 

int  main()
{
	pid_t  pid;
	int  i;

	for(i=0;  i<LOOP;  i++)
    { 
           /* 创建新进程*/
    	pid = fork();
        if  (pid < 0) { /*创建失败  */
        fprintf(stderr, “Fork Failed”);
            exit(-1);
        }
        else if (pid == 0) { /* 子进程 */
            fprintf(stdout,  “i=%d,  pid=%d,  parent  pid=%d\n”,I,      
                    getpid() ,getppid());
        }   
      }
    wait(NULL);
    exit(0);
} 


    了解了fork()之后我们再来看看exec()系统调用:系统调用exec( )加载新程序取代当前运行进程,也就是说exec调用成功时,它是相同的进程,但是运行了不同的程序代码段、堆栈和堆(heap)等也都完全重写了。它允许进程“加载”一个完全不同的程序,并从main开始执行,而我们的fork()创建出来的子进程是从fork()之后的代码段处开始执行的。

    我们接下来讨论一下fork()的实现开销:当我们使用fork()系统调用时,首先要对子进程分配内存,然后复制父进程的内存和CPU寄存器到子进程里。开销昂贵!!

    然而在99%的情况里,我们在调用fork()之后调用exec(),因为在大多数情况下我们都是不希望和父进程执行同样的代码,不然的话我们创建一个新的进程也就没有多大的意义了。这时候我们就该考虑一下这个问题了:既然不想使用父进程中的代码,在fork()操作中内存复制就是没有作用的。那么为什么不能结合它们在一个调用中?

    此后,就产生了vfork():创建进程时,不再创建一个同样的内存映像。一些时候称之为轻量级fork(),子进程几乎立即调用exec()。而在子进程调用exec()之前,暂时与父进程共享地址空间


    我们注意到了,前面fork()的示例代码中使用了wait()函数,那么这个函数是干什么用的呢?这就要引出一个新的概念了:父进程等待子进程

    wait()系统调用用于父进程等待子进程的结束:子进程结束时通过exit()向父进程返回一个值,父进程通过wait()接受并处理返回值

    wait()系统调用的功能:有子进程存活时,父进程进入等待状态,等待子进程的返回结果。当某子进程调用exit()时,唤醒父进程,将exit()返回值作为父进程中wait的返回值

    既然子进程结束时是通过exit()向父进程返回一个值,那么我们又要学习一下exit()系统调用了:

    进程结束执行时调用exit(),完成进程资源回收

    exit()系统调用的功能:

  •     将调用参数作为进程的“结果”
  •     关闭所有打开的文件等占用资源
  •     释放内存
  •     释放大部分进程相关的内核数据结构
  •     检查是否父进程是存活着的,如存活,保留结果的值直到父进程需要它,进入僵尸(zombie/defunct)状态。如果没有,它释放所有的数据结构,进程结果
  •     清理所有等待的僵尸进程

    说到这里,大家可能对僵尸进程有点疑惑:所谓的僵尸进程,就是父进程没有调用wait收集子进程的退出状态,子进程就已经退出了,此时这个退出的子进程就成为了僵尸进程,它的很多进程资源都还没有释放(例如PID在进程表中仍然存在)。   

版权声明:本文为博主原创文章,未经博主允许不得转载。

Linux进程fork,exec,vfork详解

标签:linux   fork   exec   vfork   进程   

原文地址:http://blog.csdn.net/baidu_28312631/article/details/47614119

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!