最后编辑: 2019-11-6

版本: gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.11)

一、进程标识

每一个进程都有一个唯一的非负整数的ID, 该类型为 pid_t. 当进程退出或者被杀死后,进程 ID 会被系统复用. 与文件句柄不同的是,大多操作系统使用的是延迟复用算法,这为了避免新的进程被误认为是某个已经被中止的先前进程.(顺次向下使用).

系统中存在一些专有进程,例如 ID = 0 的调度进程(交换进程 swapper), ID = 1 的 init 进程. init 进程是所有进程的祖先进程.

1.1 相关函数

pid_t getpid(void); // 获取当前进程的 ID 

pid_t getppid(void); // 获取父进程的 ID

二、fork 函数

fork 函数可用于创建一个新的进程, 新的进程称为当前进程的子进程, 相对的,当前进程也就是新进程的父进程.

pid_t fork(void);
  1. fork 调用一次返回两次. 两次返回的区别在于, 子进程返回 0, 父进程返回新建子进程的进程 ID

    • 父进程返回新建子进程 ID 原因: 一个进程可以有多个子进程,但是系统没有一个函数能获取所有子进程 ID;
    • 子进程返回值为 0 的原因: 子进程可以通过 getppid 获取父进程 ID, (ID为0的就交换进程永远只会内核交换时候使用,子进程的父进程永远不能为0);
    • 返回值小于 0 表示异常
  2. 子进程与父进程继续执行 fork 之后的指令.子进程是父进程的副本. 但目前很多实现上采用写时复制技术(Copy-On-Write), fork 之后, 父子进程区域共享,但该区域变更为只读状态,当父进程或者子进程想要对该区域进行修改的时候, 内核将为父进程或子进程复制一份该区域作为副本使用.(谁修改,谁复制).

  3. fork 之后父子进程的调度先后顺序是不确定的,这取决于内核的调度算法;

2.1 父子进程之间的区别:

前面说到, 子进程是父进程的副本. 但是还是有如下的区别:

  1. fork 返回值不同;
  2. 进程的 ID 不同;
  3. 父进程的 ID 也不同;
  4. 子进程的 tms_utime/ tms_stime / tms_cutime / tms_ustime 的值设置为 0;
  5. 子进程不继承父进程设置的文件锁;
  6. 子进程的未处理闹钟被清除;(未决信号清零)
  7. 子进程的未处理信号集设置为空集;

2.2 fork 使用场景

  1. 父进程希望复制自己, 例如网络服务中,父进程等待请求,接收到请求后 fork 自己,让子进程去处理请求, 父进程继续等待下一个请求;
  2. 一个进程要执行不同的程序. 例如 shell 终端;

2.3 代码示例

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> int globvar = 6;
char buf[] = "a write to stdout \n"; int main(int argc, char **argv)
{
int var;
pid_t pid; var = 88; if (write(STDOUT_FILENO, buf, sizeof(buf) - 1) != sizeof(buf) - 1)
{
perror("write error");
} printf("before fork \n"); // not flush stdout if ((pid = fork()) < 0)
{
perror("fork error ");
}
else if (pid == 0) // child
{
globvar++;
var++;
}
else // parent
{
sleep(2); // 等待子进程先执行
} printf("pid = %d, glob = %d, var = %d \n", getpid(), globvar, var);
exit(0);
}

执行结果:

a write to stdout
before fork
pid = 6053, glob = 7, var = 89
pid = 6052, glob = 6, var = 88

fork 打印结果重定向到文件内部, 多次打印文件内容, fork 之前需要调用 fflush() 刷新流

  1. 终端是标准的输出设备,标准输出设备是行缓冲模式,当有 \n 的时候, 会刷新缓冲区
  2. 文件是全缓冲模式, 全缓冲模式下 \n 仅仅是一个换行的作用

三、vfork 函数

此函数有瑕疵, 仅作了解

vfork 与 fork 调用的序列和返回值相同,但是两者语义上不同的.

vfork 函数创建的新进程,该进程的目的是 exec 一个新函数. vfork 的子进程不会将父进程地址空间完全复制过去, 因为该进程目的是调用 exec. 但是, 在子进程 exec 或者 exit 之前, 子进程是在父进程的空间内运行, 这种在一定程度上提高效率.

但如果子进程修改了父进程的数据,或者调用其他的函数,又或者没有 exec / exit返回, 都会产生未知错误. vfork 保证子进程优先被返回,但是如果子进程依赖于父进程的某个动作,这样就造成死锁.

说了这么多,就是说一句, 不要用 vfork

APUE学习之进程控制 - fork 与 vfork的更多相关文章

  1. 进程控制fork与vfork

    1. 进程标识符 在前面进程描述一章节里已经介绍过进程的两个基本标识符pid和ppid,现在将详细介绍进程的其他标识符. 每个进程都有非负的整形表示唯一的进程ID.一个进程终止后,其进程ID就可以再次 ...

  2. Linux网络编程学习(三) ----- 进程控制实例(第三章)

    本节主要介绍一个进程控制的实例,功能就是在前台或者后台接收命令并执行命令,还能处理由若干个命令组成的命令行,该程序命名为samllsh. 基本逻辑就是 while(EOF not typed) { 从 ...

  3. Linux网络编程学习(二) ----- 进程控制(第三章)

    1.进程和程序 程序是一个可执行文件,而一个进程是一个执行中的程序实例.一个进程对应于一个程序的执行,进程是动态的,程序是静态的,多个进程可以并发执行同一个程序.比如几个用户可以同时运行一个编辑程序, ...

  4. 进程控制fork vfork,父子进程,vfork保证子进程先运行

    主要函数: fork 用于创建一个新进程 exit 用于终止进程 exec 用于执行一个程序 wait 将父进程挂起,等待子进程结束 getpid 获取当前进程的进程ID nice 改变进程的优先级 ...

  5. APUE8进程控制 fork vfork exec

  6. 【APUE | 08】进程控制

    函数fork 博文链接: 1. 代码示例: #include "apue.h" ; char buf[] = "a write to stdout\n"; in ...

  7. linux c学习笔记----进程创建(fork,wait,waitpid)

    1.pid_t fork(); (1)当一个进程调用了fork 以后,系统会创建一个子进程.这个子进程和父进程不同的地方只有他的进程ID 和父进程ID,其他的都是一样.就象符进程克隆(clone)自己 ...

  8. APUE学习之---------------进程

    离职了,交接期也有足够的时间了,可以在好好的再看一下APUE,想想上次详细的看还是在两年之前,虽然中间也偶尔会翻出来看看,但是由于工作上交集相对比较少一直没有去细读一下.现在正好是一段空挡期可以好好看 ...

  9. APUE第八章-进程控制

    一.进程标识 二.函数fork 1.写时复制,copy-on-write 2.文件共享,父进程等待子进程完成,子进程结束后,它对任一共享描述符的读写操作的文件偏移量已做相应的更新,同时操作时,可以考虑 ...

随机推荐

  1. # jsp及servlet学习笔记

    目录 jsp及servlet学习笔记 JSP(Java Server Page Java服务端网页) 指令和动作: servlet(小服务程序) jsp及servlet学习笔记 JSP(Java Se ...

  2. 附录1:arrayanalysis的本地使用(质量控制)

    访问:https://github.com/BiGCAT-UM/affyQC_Module,点击“Download ZIP”,下载得到affyQC_Module-master.zip,解压得到一个af ...

  3. ASP.NET配置KindEditor文本编辑器

    文本编辑器:CKEditor和CKFinder  KindEditor 1.KindEditor KindEditor 是一套开源的在线HTML编辑器,主要用于让用户在网站上获得所见即所得编辑效果,开 ...

  4. Redis windows服务器配置可远程连接

    Redis配置远程可访问:修改redis.conf或redis.windows-service.conf配置文件. 具体通过 1:将绑定的本机给注释掉,找到这行 bind 127.0.0.1,然后在前 ...

  5. Halide安装指南release版本

    Halide安装指南 本版本针对Halide release版本 by jourluohua 使用的是Ubuntu 16.04 64位系统默认Gcc 4.6 由于halide中需要C++ 11中的特性 ...

  6. java网络编程+通讯协议的理解

    参考: http://blog.csdn.net/sunyc1990/article/details/50773014 网络编程对于很多的初学者来说,都是很向往的一种编程技能,但是很多的初学者却因为很 ...

  7. 关于Java中线程取值并返回的方法

    如何让一个线程不断跑起来,并且在取到值的时候能返回值而线程能继续跑呢? 我们都知道可以用Callable接口获得线程的返回值,或者触发事件监听来操作返回值,下面我将介绍另一种方法. public ab ...

  8. 孕期出血是否先兆流产——B超看婴儿是否在子宫内+hcg值是否过低孕激素不足

    转自:http://blog.sina.com.cn/s/blog_4a869c130102e7nu.html 很多人都经历过孕早期阴道出血,但结局大不一样. 人类受孕后,从一个单细胞逐渐发育成为一个 ...

  9. WIndows cmd command 指令总结

    1. 文件操作 显示当前文件夹内所有文件 dir dir /s 仅显示特定后缀的文件 # 查找当前目录下所有mp3文件dir /s *.mp3

  10. 清北学堂dp图论营游记day1

    讲课人: 老师对dp的理解是类似于分治思想,由小状态推出大状态.不同的是分治算法没有重叠子问题. dp把子问题越划越小,从而推出了基础状态.然后是dp方程,要满足简洁性,并且充分描述能够影响最后结果的 ...