二十二、Linux 进程与信号---进程创建
22.1 fork 和 vfork 函数
22.1.1 函数说明
#include <unistd.h>
#include <sys/types.h>
pid_t fork( void);
- 函数说明:
- 一个现有进程可以调用fork函数创建一个新进程。
- 由fork创建的新进程被称为子进程(child process)。
- fork函数被调用一次但返回两次。
- 两次返回的唯一区别是子进程中返回 0 值而父进程中返回子进程 ID。
- 子进程是父进程的副本,它将获得父进程数据空间、堆、栈等资源的副本。
- 注意,子进程持有的是上述存储空间的“副本”,这意味着父子进程间不共享这些存储空间。
- UNIX将复制父进程的地址空间内容给子进程,因此,子进程有了独立的地址空间。
- 在不同的UNIX (Like)系统下,我们无法确定fork之后是子进程先运行还是父进程先运行,这依赖于系统的实现。
- 所以在移植代码的时候我们不应该对此作出任何的假设。
- 函数返回值:
- 子进程中为 0,父进程中为子进程 ID,出错为 -1
- 子进程的继承属性
- 用户信息和权限、目录信息、信号信息、环境、共享存储段、资源限制、堆、栈和数据段,共享代码段。
- 子进程特有属性
- 进程 ID、锁信息、运行时间、未决信号
- 操作文件时的内核结构变化
- 子进程只继承父进程的文件描述表,不继承但共享文件表项和 i-node。
- 父进程创建一个子进程后,文件表项中的引用计数器加1变成2,当父进程作 close 操作后,计数器减 1,子进程还是可以使用文件表项,只有当计数器为 0 时,才会释放文件表项。
#include <unistd.h>
pid_t vfork(void);
- 函数说明
- vfork()会产生一个新的子进程,其子进程会复制父进程的数据与堆栈空间,并继承父进程的用户代码,组代码,环境变量、已打开的文件代码、工作目录和资源限制等。
- Linux 使用 copy-on-write(COW)技术,只有当其中一进程试图修改欲复制的空间时才会做真正的复制动作,由于这些继承的信息是复制而来,并非指相同的内存空间,因此子进程对这些变量的修改和父进程并不会同步。
- 此外,子进程不会继承父进程的文件锁定和未处理的信号。
- 注意,Linux不保证子进程会比父进程先执行或晚执行,因此编写程序时要留意死锁或竞争条件的发生。
- 返回值
- 如果 vfork()成功则在父进程中会返回新建立的子进程代码(PID),而在新建立的子进程中则返回 0。
- 如果 vfork 失败则直接返回-1,失败原因存于errno中。
- 错误代码
- EAGAIN 内存不足。
- ENOMEM 内存不足,无法配置核心所需的数据结构空间。
两个函数的附加说明:
- fork 创建的新进程被称为子进程,该函数被调用一次,但返回两次。两次返回的区别是:在子进程中的返回值是 0,而在父进程中的返回值则是新子进程的进程 ID。
- 创建子进程,父子进程哪个先运行根据系统调度且子进程会复制父进程的内存空间
- vfork 创建的子进程会先运行,但不会复制父进程的内存空间
22.1.2 例子
22.1.2.1 查看父子进程的运行
process_fork.c
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h> int main(void)
{
printf("pid: %d", getpid()); pid_t pid;
pid = fork();//创建子进程
//在 fork 后,会运行两个进程(父进程和子进程)
if(pid < ) {
perror("fork error");
} else if(pid > ) {
//父进程(在父进程中返回的是子进程的 pid)
//父进程执行的代码
printf("I am parent process pid is %d, ppid is %d, fork return is %d\n",
getpid(), getppid(), pid);
} else {
//子进程(在子进程中 fork 返回的是0)
//子进程执行的代码
printf("I am child process pid is %d, ppid is %d, fork return is %d\n",
getpid(), getppid(), pid);
} //这里的代码是父子进程都要执行的代码
printf("pid: %d\n", getpid());
sleep(); return ;
}

可以看见 父子进程的 pid 是不同的,父进程中通过fork 获得是子进程的ID号,子进程的父进程是102839,fork 后返回的是0
子进程的ID 和 父进程的ID 在公共代码区都打印了出来。
22.1.2.2 两进程循环启动后,各自输出内容
/* 父子进程交替运行 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> int main(void)
{
printf("current pid : %d\n", getpid()); pid_t pid = fork();
if(pid < ) {
perror("fork error");
} else if(pid > ) {
//父进程执行
int i;
for(i = ; i < ; i++) {
printf("This is parent process pid is : %d\n", getpid());
sleep();
}
} else {
//子进程
int i;
for(i = ; i < ; i++) {
printf("This is child process pid is : %d\n", getpid());
sleep();
}
} return ;
}
编译运行:

虽然设置了交替运行,但是不是真的交替运行,这个与系统调度来决定的。
22.1.2.3 子进程内存的复制

案例:
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h> int g_val = ;//全局变量,存放在数据段 int main(void)
{
int a_val = ;//局部变量,调用的时候存放在栈中
static int s_val = ;//静态变量,存放在数据段
printf("pid: %d", getpid()); pid_t pid;
pid = fork();//创建子进程
//在 fork 后,会运行两个进程(父进程和子进程)
if(pid < ) {
perror("fork error");
} else if(pid > ) {
//父进程(在父进程中返回的是子进程的 pid)
//父进程执行的代码
g_val = ;
a_val = ;
s_val = ; printf("I am parent process pid is %d, ppid is %d, fork return is %d\n",
getpid(), getppid(), pid);
printf("g_val: %p, a_val: %p, s_val: %p\n", &g_val, &a_val, &s_val);
} else {
//子进程(在子进程中 fork 返回的是0)
//子进程执行的代码
g_val = ;
a_val = ;
s_val = ;
printf("I am child process pid is %d, ppid is %d, fork return is %d\n",
getpid(), getppid(), pid);
printf("g_val: %p, a_val: %p, s_val: %p\n", &g_val, &a_val, &s_val);
} //这里的代码是父子进程都要执行的代码
printf("pid: %d, g_val: %d, a_val: %d, s_val: %d\n", getpid(), g_val, a_val, s_val);
sleep(); return ;
}

可以看见变量所在的虚拟地址都是一样的,但是输出的值却不一样。
值不一样是因为,物理空间不一样,子进程和父进程指向的物理空间不一样。数据段、堆和栈都由各自的物理空间。虚拟内存存放的数据最终都会存放在物理地址上。最终修改的也是物理内存中的内容。程序中最终输出的也是物理地址的内容。

二十二、Linux 进程与信号---进程创建的更多相关文章
- Linux学习之CentOS(二十六)--Linux磁盘管理:LVM逻辑卷的创建及使用
在上一篇随笔里面 Linux学习之CentOS(二十五)--Linux磁盘管理:LVM逻辑卷基本概念及LVM的工作原理,详细的讲解了Linux的动态磁盘管理LVM逻辑卷的基本概念以及LVM的工作原理, ...
- JAVA基础知识总结:一到二十二全部总结
>一: 一.软件开发的常识 1.什么是软件? 一系列按照特定顺序组织起来的计算机数据或者指令 常见的软件: 系统软件:Windows\Mac OS \Linux 应用软件:QQ,一系列的播放器( ...
- 智课雅思词汇---二十二、-al即是名词性后缀又是形容词后缀
智课雅思词汇---二十二.-al即是名词性后缀又是形容词后缀 一.总结 一句话总结: 后缀:-al ②[名词后缀] 1.构成抽象名词,表示行为.状况.事情 refusal 拒绝 proposal 提议 ...
- [分享] IT天空的二十二条军规
Una 发表于 2014-9-19 20:25:06 https://www.itsk.com/thread-335975-1-1.html IT天空的二十二条军规 第一条.你不是什么都会,也不是什么 ...
- Bootstrap <基础二十二>超大屏幕(Jumbotron)
Bootstrap 支持的另一个特性,超大屏幕(Jumbotron).顾名思义该组件可以增加标题的大小,并为登陆页面内容添加更多的外边距(margin).使用超大屏幕(Jumbotron)的步骤如下: ...
- Web 前端开发精华文章推荐(HTML5、CSS3、jQuery)【系列二十二】
<Web 前端开发精华文章推荐>2014年第一期(总第二十二期)和大家见面了.梦想天空博客关注 前端开发 技术,分享各类能够提升网站用户体验的优秀 jQuery 插件,展示前沿的 HTML ...
- 二十二、OGNL的一些其他操作
二十二.OGNL的一些其他操作 投影 ?判断满足条件 动作类代码: ^ $ public class Demo2Action extends ActionSupport { public ...
- WCF技术剖析之二十二: 深入剖析WCF底层异常处理框架实现原理[中篇]
原文:WCF技术剖析之二十二: 深入剖析WCF底层异常处理框架实现原理[中篇] 在[上篇]中,我们分别站在消息交换和编程的角度介绍了SOAP Fault和FaultException异常.在服务执行过 ...
- VMware vSphere 服务器虚拟化之二十二桌面虚拟化之创建View Composer链接克隆的虚拟桌面池
VMware vSphere 服务器虚拟化之二十二桌面虚拟化之创建View Composer链接克隆的虚拟桌面池 在上一节我们创建了完整克隆的自动专有桌面池,在创建过程比较缓慢,这次我们将学习创建Vi ...
- Bootstrap入门(二十二)组件16:列表组
Bootstrap入门(二十二)组件16:列表组 列表组是灵活又强大的组件,不仅能用于显示一组简单的元素,还能用于复杂的定制的内容. 1.默认样式列表组 2.加入徽章 3.链接 4.禁用的列表组 5. ...
随机推荐
- sublime text3 插件的安装
ctrl + shift +p 打开搜索框界面 安装: 输入install package并回车,再在列表中选中所需要安装的插件,你会发现左下角正在显示安装.安装成功后,一般会打开插件说明. 卸载: ...
- 前端基础-- CSS
CSS知识 CSS(Cascading Style Sheet,层叠样式表)定义如何显示HTML元素. 当浏览器读到一个样式表,它就会按照这个样式表来对文档进行格式化(渲染).Css之车更丰富的文档外 ...
- ACM-ICPC 2017 Asia Xi'an A XOR (线性基+线段树思想)
题目链接 题意;给个数组,每次询问一个区间你可以挑任意个数的数字异或和 然后在或上k的最大值 题解:线性基不知道的先看这个,一个线性基可以log的求最大值把对应去区间的线性基求出来然后用线段树维护线性 ...
- Surface Pro 4 系统优化全教程及QA
甲.如何根据你的需求选择相应版本的surface1.Core M3-6Y30,Core i5-6300U,Core i7-6650U的性能差距有多大?2.HD 515,HD520,Iris 540的性 ...
- Docker的脚本安装
官方镜像支持 curl -sSL https://get.docker.com/ | sh 国内镜像站 curl -sSL https://get.daocloud.io/docker | sh cu ...
- 【SDOI2008】仪仗队
//裸的欧拉函数//y=kx//求不同的k有多少#include<bits/stdc++.h> #define ll long long #define N 40010 using nam ...
- ImageMagick: win7 | win8 & uac (用户帐户控制) 注册表的一些事
现在用win7,win8的人越来越多了, 程序在一些 win 7, win8 上运行会遇到一些之前没想过的兼容性问题. 比如 64位系统运行32位程序时的注册表重定向,还有因为 uac (用户帐户控制 ...
- MFC读写配置ini文件
https://blog.csdn.net/naibozhuan3744/article/details/78783446 https://blog.csdn.net/rayborn1105/arti ...
- Redis:默认配置文件redis.conf详解
转: Redis:默认配置文件redis.conf详解 # Redis配置文件样例 # Note on units: when memory size is needed, it is possibl ...
- GUI 设计
GUI(图形化界面编程) Graphical User Interface (java.Awt javax.Swing) CLI(命令行操作接口) Command line User ...