Linux_ fork 进程操作

  1. 什么是进程

    程序的运行实例,就是“进程”
    一个程序,同时执行多次,则产生多个不同的进程。

    程序是静态的
    进程是动态的

  2. 进程的结构
    进程的组成:程序代码、数据、变量、文件描述符(表示已打开的文件)、环境等组成。

    每个进程有一个唯一的编号,称为”进程标识符”(PID)
    PID >= 2
    PID=1的进程是init进程。

    进程之间共享程序代码
    即,同一个程序的多个进程,共享一个代码拷贝。

    进程之间共享函数库。

    进程有自己的”栈空间”、“程序计数器”、变量。

  3. 进程表
    Linux把所有进程的相关信息放在一个表中,称为进程表
    每个进程是一个表项。
    进程表的索引,是PID

    可同时运行的进程数取决于该进程表的容量。

  4. 进程的查看
    ps 显示与该终端连接的进程。
    ps -ef
    ps ax

  5. 进程的状态
    ps ax
    ps的stat列表示进程的状态:
    S: 睡眠,即“挂起”,等待某个事件的发生。
    R: 运行
    D: 不可中断的睡眠
    T: 停止
    Z: 死进程(僵尸进程)
    s: 进程是会话期的首进程。
    +:进程属于前台进程

  6. 进程的调度
    单处理器上,同一个时刻只能有一个进程运行。
    Linux内核用“进程调度器”来决定下一个时间片执行哪个进程。

  7. 进程的启动
    1)system
    实例:main7.c

    在程序的内部,创建一个新进程,执行指定的shell命令。
    
    主进程将等待新进程执行结束后,才能继续执行。
    除非新进程以后台方式运行,system("ls &") 
    
    效率不高,因为要先启动shell, 然后再运行指定的shell命令。
    

    2) exec (进程替换)
    exec指一组函数.
    用于:从当前进程切换到另一个程序执行,且不返回到原来的程序(除非发生了错误,返回-1)。

    "l"组 (l即list, 新程序的参数为列表形式,即可变参数列表)
    execl
    execlp
    execle
    
    “v"组(v即vector, 新程序的参数为数组形式, 参数个数不变
    execv
    execvp
    execve
    
    p后缀:
    第一个参数是要执行的文件名,不含路径。
    文件的路径由系统默认的环境变量(path)指定。
    
    e后缀:
    最后一个参数是字符串数组,表示指定的环境变量。
    注意,这个环境变量是指程序替换以后,
          新程序运行期间的环境变量。
      而不是替换新程序时的环境变量,
      所以execle函数的第一个参数仍然需要使用路径。
      替换到新程序以后,此时的环境就是execle的最后一个参数。
    
    实例:main8.c
    分别用以上六种形式,创建"ls -l"进程。
    
    注意:
    exec启动的新进程继承原进程的很多特性:
    比如,原进程中打开的文件描述符,在新进程中仍保持打开。
    

    3) fork (进程复制)
    复制的新进程(子进程),与原进程一模一样,
    但有自己的数据空间、环境、文件描述符等。

     fork的返回值
     在原进程(父进程)中,fork返回新进程(子进程)的PID
     在新进程(子进程)中,fork返回0
     fork失败,返回-1
           失败原因:父进程能拥有的子进程数超出限制(CHILD_MAX)
                          进程表中的空间不足
                          虚拟内存不足
    

    实例:main9.c

  8. 等待子进程结束
    1) wait
    功能:父进程等待任意它的任一个子进程结束
    返回该结束子进程的PID
    参数: 实参非空时,返回子进程的退出状态。
    参见man 2 wait

    实例:main10.c

    2) waitpid
    功能:父进程等待指定的子进程。
    参数:
    详见man 2 waitpid
    参数3常使用WNOHANG(不阻塞,立即返回)
    实例:
    waitpid(child_pid, (int*)0, WNOHANG);
    如果子进程未结束、未终止,则返回0
    已经子进程已结束, 则返回子进程的PID
    如果失败, 返回-1

    1. 僵尸进程

      1) 什么是僵尸进程
      僵死进程(死进程):是指该进程已经结束运行,但在进程表中还没有删除它的相关信息。

      2)僵死进程产生的原因
      子进程比父进程先结束,(儿子比父亲先“死”)
      但是又不能在进程表中删除子进程的表项,因为父进程调用wait时还需要这些信息。

      3)僵尸进程的“归宿”
      子进程比父进程先结束后,成为僵尸进程。
      直到父进程也结束,该僵尸进程才真正消亡(从进程表中删除其表项)

      如果父进程被异常终止,则该僵尸进程认init进程为“父进程”
      init进程发现该僵尸子进程后,再把它清除。

      应该尽量避免产生僵尸进程。
      僵尸进程虽不再运行,但仍占用系统的资源!

      main11.c
      测试:gcc main11.c
      ./a.out &
      ps /* 子进程结束后 */

你知道:

 for (i=0; i<2; i++) { fork(); }
   一共创建了多少个进程?

你可能感兴趣的:(linux,fork)