小何讲进程: Linux进程控制编程 (fork、vfork)

所谓进程控制,就是系统使用一些具有特定功能的程序段来创建进程、撤消进程以及完成进程在各种状态之间的转换,

从而达到多进程高效率并发执行和协调资源共享的目的。进程控制是进程管理和处理机管理的一个重要任务。

1. fork()创建进程

在Linux系统中,除了系统启动之后的第一个进程(根进程)由系统来创建外,

其余所有进程都必须由已存在的进程来创建新创建的进程叫子进程,而创建子进程的进程叫父进程,

具有相同父进程的进程叫兄弟进程。

在Linux中创建一个新进程的方法是使用fork()函数。

fork()函数用于根据已存在的进程以“复制”的方式创建一个子进程。

调用fork()时,fork()将父进程所有的资源通过数据结构的"复制"传给子进程:

让子进程与父进程使用同一代码段

将父进程的数据段和堆栈段复制一份给子进程,这样父进程的所有数据都可以留给子进程,

但父子进程的地址空间已经分开,不再共享任何数据,因此,相互之间不再有影响。

子进程的执行独立于父进程,父子进程的数据共享需要通过专门的通信机制。

采用“复制”的方法创建子进程控制块

把复制这个词加上引号,是因为这个复制并不是完全复制。因为父进程控制块中某些项的内容必须按照子进程的特点来修改,

如:进程的标识、状态等。另外,子进程控制块还必须有表示自己父进程的域及私有空间,如数据空间、用户堆栈等。

使用fork()函数得到的子进程是父进程的一个“复制品”,它从父进程处继承了整个进程的地址空间:

包括进程上下文、代码段、进程堆栈、内存信息、打开的文件描述符、信号控制设定、进程优先级、进程组号、

当前工作目录、根目录、资源限制和控制终端等,而子进程所独有的只有它的进程号、资源使用和计时器等少量信息。

父、子两个进程运行同一个程序:

因为子进程几乎是父进程的完全复制,所以父子两个进程会运行同一个程序。

因此需要用一种方式来区分它们,否则,这两个进程不可能做不同的事。

子进程中,fork()返回0

父进程中,fork()返回子进程的ID(>0)

实际上是在父进程中执行fork()函数时,父进程会复制出一个子进程,而且父子进程的代码从fork()函数的返回开始分别在两个地址空间中同时运行。

从而两个进程分别获得其所属fork()的返回值,其中在父进程中fork()的返回值是子进程的进程号,而在子进程中fork()返回0。

因此,可通过返回值来判定该进程是父进程还是子进程。

若fork()创建进程失败,则返回-1。

fork()系统调用的工作流程示意图:

fork()函数的不足:

使用fork()函数时,它“复制”了父进程中的代码段、数据段和堆栈段里的大部分内容,使得fork()函数的系统开销比较大。

当创建一个子进程后,子进程接下来调用exec()执行另一个程序,那么前面的复制工作将是多余的

如果调用fork()函数的程序的数据段和堆栈段都很大,那么复制工作的开销会严重影响系统性能。

解决办法:采用copy-on-write(写时复制)技术。

复制时只是“逻辑”上的,并非“物理”上的:实际执行fork()时,物理空间上两个进程的数据段和堆栈段都还是共享着的,

当有一个进程写了某个数据时,这时两个进程之间的数据才有了区别,此时系统就将有区别的“页”从物理上分离,

这样系统在空间上的开销就可以达到最小。

fork()函数举例:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>

int main()
{
	pid_t result;
	result=fork();
	if(result==-1)
	{
		printf("FORK ERROR!\n");
	}
	else if(result==0)
	{
		printf("In child process PID is %d \n The returned value is %d \n\n",getpid(),result);
	}
	else
	{
		printf("In father process PID is %d \n The return value is %d \n\n",getpid(),result);
	}

	return result;
}

运行截图如下:

2.  vfork():

vfork是linux提供的另一个用来生成一个子进程的系统调用。

与fork的区别:vfork并不把父进程全部复制到子进程中,而只是用复制指针的方法使子进程和父进程的资源实现共享。

因为通常创建新进程的目的是 exec一个新程序,所以vfork不产生父进程的副本,可提高效率。

vfork与fork一样都创建一个子进程,但是它并不将父进程的地址空间完全复制到子进程中,因为子进程会立即调用 exec (或exit ),

不过在子进程调用 exec或exit之前,它在父进程的空间中运行。

vfork保证子进程先于父进程运行,只有当子进程调用exec或exit后,父进程才能被调度运行。

用vfork()创建的子进程不能用return返回,只能用exit()或_exit()退出。而用fork()创建的子进程可以用return返回。

3. 对比fork()和vfork()函数,观察之间的区别

(1)调用fork()函数:

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
	pid_t result;
	int  data=5;
	result = fork(); 	/*调用fork()函数*/
	if(result ==  -1)	/*首先进行出错处理*/
	    	  printf("Fork error\n");
	else if (result == 0) 	/*返回值为0代表子进程*/
	{
		data++;
	 	printf("data=%d,child\'s PID=%d\n",data,getpid());
	}
	else			 /*返回值大于0代表父进程*/
	{
		data++;
	        printf("data=%d,father\'s PID=%d\n",data,getpid());
	}
	exit(1);
}

运行截图:

(2)调用vfork()函数:

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
	pid_t result;
	int  data=5;
	result = vfork(); 	/*调用fork()函数*/
	if(result ==  -1)	/*首先进行出错处理*/
	    	  printf("Fork error\n");
	else if (result == 0) 	/*返回值为0代表子进程*/
	{
		  data++;
	 	  printf("data=%d,child\'s PID=%d\n",data,getpid());
	}
	else			 /*返回值大于0代表父进程*/
	{
		  data++;
	          printf("data=%d,father\'s PID=%d\n",data,getpid());
	}
	exit(1);
}

运行截图:

时间: 2024-12-14 18:10:58

小何讲进程: Linux进程控制编程 (fork、vfork)的相关文章

Linux下1号进程的前世(kernel_init)今生(init进程)----Linux进程的管理与调度(六)

日期 内核版本 架构 作者 GitHub CSDN 2016-05-29 Linux-4.5 X86 & arm gatieme LinuxDeviceDrivers Linux进程管理与调度-之-进程的创建 前言 Linux下有3个特殊的进程,idle进程(PID=0), init进程(PID=1)和kthreadd(PID=2) * idle进程由系统自动创建, 运行在内核态 idle进程其pid=0,其前身是系统创建的第一个进程,也是唯一一个没有通过fork或者kernel_thread产

Linux下0号进程的前世(init_task进程)今生(idle进程)----Linux进程的管理与调度(五)

日期 内核版本 架构 作者 GitHub CSDN 2016-05-12 Linux-4.5 X86 & arm gatieme LinuxDeviceDrivers Linux进程管理与调度-之-进程的创建 前言 Linux下有3个特殊的进程,idle进程(PID = 0), init进程(PID = 1)和kthreadd(PID = 2) * idle进程由系统自动创建, 运行在内核态 idle进程其pid=0,其前身是系统创建的第一个进程,也是唯一一个没有通过fork或者kernel_t

Linux进程管理与调度-之-目录导航【转】

转自:http://blog.csdn.net/gatieme/article/details/51456569 版权声明:本文为博主原创文章 && 转载请著名出处 @ http://blog.csdn.net/gatieme 目录(?)[-] 项目链接 进程的描述 进程的创建 进程的加载与运行 进程的退出 进程的调度 调度普通进程-完全公平调度器CFS 日期 内核版本 架构 作者 GitHub CSDN 2016-07-21 Linux-4.6 X86 & arm gatieme

Linux进程初识

随便说说 最近在实习, 公司里面用的电脑系统里面是ubuntu, 之前在学校里也用装过这个系统, 当时也就是试试玩着, 简单地熟悉里面的几个命令而已(ls,  cd , mkdir ,就这么多了*_*!).但是在公司实习已经快四个月,让我对Linux使用有了很大进步,最近觉得自己应该对这个优秀的作品有深入的了解.于是在学校图书馆借了几本关于Linux内核相关的书籍.主要是<<Linux内核设计与实现>>作者是Robert Love,借的时候还有意的选了英文版的, 因为实习的过程当中

Linux下的编程实战【转】

一篇比较不错的文章, 降到了 makefile make , gcc编译器,GDB调试器, Linux文件系统,Linux文件API,.C语言库函数(C库函数的文件操作实际上是独立于具体的操作系统平台的),进程控制与进程通信编程 1.Linux进程 Linux进程在内存中包含三部分数据:代码段.堆栈段和数据段.代码段存放了程序的代码.代码段可以为机器中运行同一程序的数个 进程共享.堆栈段存放的是子程序(函数)的返回地址.子程序的参数及程序的局部变量.而数据段则存放程序的全局变量.常数以及动态数

Linux进程控制编程

一.获取ID #include<sys/types.h> #include<unistd.h> pid_t getpid(void)    获取本进程ID pid_t getppid(void)  获取父进程ID 父进程:现有进程中,创建新的进程. 例:getpid.c #include<stdio.h> #include<unistd.h> #include<stdlib.h> int main() { printf("PID=%d\

小何讲进程: 编写Linux守护进程方法详解

守护进程概述 守护进程,也就是通常所说的Daemon进程,是Linux中的后台服务进程. 它是一个生存期较长的进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些事件的发生. 守护进程常常在系统引导载入时启动,在系统关闭时终止. Linux有很多系统服务,大多数服务都是通过守护进程实现的.守护进程的名字通常以d结尾,字母d就是Daemon的意思. 由于在Linux中,每一个系统与用户进行交流的界面称为终端,每一个从此终端开始运行的进程都会依附于这个终端,这个终端就称为这些进程的控制终端

小何讲进程: Linux进程的基本概念

1.  进程定义 进程是操作系统理论的核心与基础,操作系统中的许多概念都和进程相关. 进程的定义 ,进程有过各种各样的定义,现列举较为著名的几种. 进程是一个独立的可调度的活动: 进程是一个抽象实体,当它执行某个任务时,要分配和释放各种资源: 进程是可以并行执行的计算单位: 进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动: 进程是一个程序的一次执行过程,同时也是资源分配的最小单元. 进程和程序是有本质区别的: 程序是静态的,它是一些保存在磁盘上的指令的有序集合,没有任何执行的概念

linux(六)__进程与任务控制

一.程序.进程.线程 1.程序是一个普通文件,是一系列指令和数据的集合,是一个静态的实体,是程序员写好之后存储于外设之上的代码.它是"死"的,而进程和程序都是"活"的. 2.进程是程序的执行实例,即运行中的程序,同时也是程序的一个副本:程序是放置于磁盘的,而程序是位于内存中的.每一个进程都分配一个ID号. 每一个进程,都会对应一个父进程,而这个父进程可以复制多个子进程.例如WWW服务器. 3.线程是比进程更小的执行单元,一个进程至少包括一个线程.一个进程要想同时在多