基础文章3:进程基础之fork函数
来源:互联网 发布:软件开发说明书 编辑:程序博客网 时间:2024/05/16 01:24
0.序
1.基础内容介绍
1)进程的组成:
2)fork函数调用后,系统所做工作:
2.函数详细介绍
1)函数原型
2)作用
3)描述
3.总结:
fork函数是Linux中创建进程的函数,也是唯一一个创建进程的函数。因此学好fork函数时基础中的基础。0.序
1.基础内容介绍
1)进程的概述:
进程简单的说就是一个程序一次执行的过程,它是一个动态的概念。按照教科书上的定义,进程是程序执行的实例,是linux的基本调度单位。
对于程序员来说,最重要的就是要区分进程和程序的区别,程序是指一段完成功能的代码,或者说是一个工具,它是一个静态的概念,而进程,它是动态的,比如,linux的vi编辑器,它就是一段在linux下用于文本编辑的工具,那么它是一个程序,而我们在linux终端中,可以分别开启两个vi编辑器的进程。一旦提到进程,我们的脑子里就应该产生——程序从代码的第一句动态的执行到最后一句这样的一个思路。
一个进程由如下元素组成:1.> 进程的当前上下文,即进程的当前执行状态;2.> 进程的当前执行目录3.> 进程访问的文件和目录4.> 进程的访问权限,比如它的文件模式和所有权
5.> 内存和其他分配给进程的系统资源
fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事。
#include <unistd.h>
pid_t fork(void);
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int glob = 6;
char buf[] = "a write to stdout/n";
int main()
{
int var;
pid_t pid;
var = 88;
fprintf(stderr, "%s", buf);
printf("before fork\n");
if(( pid = fork() ) < 0 )
{
fprintf(stderr, "fork error\n");
}
else if(pid == 0)
{
glob++;
var++;
printf("child process\n");
printf("pid = %d getpid = %d, father pid = %d, glob = %d, var = %d\n",pid, getpid(), getppid(), glob, var);
exit(0);
}
else
{
var += 20;
glob += 20;
printf("begin into father process\n");
sleep(2);
printf("father process\n");
printf("pid = %d, father pid = %d, glob = %d, var = %d\n", getpid(), getppid(), glob, var);
}
return 0;
}
begin into father process
child process
pid = 0 getpid = 4039, father pid = 4038, glob = 7, var = 89
father process
pid = 4038, father pid = 3317, glob = 26, var = 108
#include <stdio.h>
int main(void)
{
int i=0;
printf("i son/pa ppid pid fpid\n");
//ppid指当前进程的父进程pid
//pid指当前进程的pid,
//fpid指fork返回给当前进程的值
for(i=0;i<2;i++){
pid_t fpid=fork();
if(fpid==0)
printf("%d child %4d %4d %4d\n",i,getppid(),getpid(),fpid);
else
printf("%d parent %4d %4d %4d\n",i,getppid(),getpid(),fpid);
}
return 0;
}
i son/pa ppid pid fpid
0 parent 3317 4096 4097
1 parent 3317 4096 4098
1 child 1 4098 0
0 child 1 4097 0
1 parent 1 4097 4099
1 child 1 4099 0
2)fork函数调用后,系统所做工作:
一个进程调用fork()函数后,
(1)系统先给新的进程分配资源,例如存储数据和代码的空间。
(2)然后把原来的进程的所有值都复制到新的新进程中,只有少数值(这部分少数值在man fork中有详细说明)与原来的进程的值不同。相当于克隆了一个自己。
2.函数详细介绍
1)函数原型
SYNOPSIS#include <unistd.h>
pid_t fork(void);
2)作用
创建一个子进程。是进程不是线程。
3)描述
( 1)通过复制调用进程(即父进程)来创建一个子进程。
所谓复制:子进程会与父进程共享代码空间,但是其数据空间是相互独立的。子进程的数据空间是从父进程完成拷贝下来的,刚创建完子进程时里面的取值都与父进程一样,但是由于其数据空间是相互独立的,因此数据空间中的数据会随着子进程的进行,而发生改变,从而与父进程不再一样。
fork函数的作用是在其进程中创建一个新的进程,这个新的进程不会取代原来的进程,而是以当前进程的一个子进程而存在的。这个子进程会有一个新的进程标识符pid。并且这个子进程会继承父进程的一切!
什么是叫继承父进程的一切呢?就是克隆父进程的所有,包括父进程的代码,父进程正在执行的状态,父进程的工作目录,父进程的所有资源等等,一切的一切,fork系统调用会全部的复制下来。
举例:
/*可以用于说明父子进程间数据空间是相互独立的*/#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int glob = 6;
char buf[] = "a write to stdout/n";
int main()
{
int var;
pid_t pid;
var = 88;
fprintf(stderr, "%s", buf);
printf("before fork\n");
if(( pid = fork() ) < 0 )
{
fprintf(stderr, "fork error\n");
}
else if(pid == 0)
{
glob++;
var++;
printf("child process\n");
printf("pid = %d getpid = %d, father pid = %d, glob = %d, var = %d\n",pid, getpid(), getppid(), glob, var);
exit(0);
}
else
{
var += 20;
glob += 20;
printf("begin into father process\n");
sleep(2);
printf("father process\n");
printf("pid = %d, father pid = %d, glob = %d, var = %d\n", getpid(), getppid(), glob, var);
}
return 0;
}
运行结果
a write to stdout/nbefore forkbegin into father process
child process
pid = 0 getpid = 4039, father pid = 4038, glob = 7, var = 89
father process
pid = 4038, father pid = 3317, glob = 26, var = 108
(2)创建新进程成功后,系统中出现两个基本完全相同的进程,这两个进程执行没有固定的先后顺序,哪个进程先执行要看系统的进程调度策略。
(3)当创建完毕后,可以想象,两个进程一直同时进行,而且步调一致,在fork之后,他们分别做不同的工作,也就是分岔了,这就是为什么叫fork的原因. fork执行完毕后,出现两个进程。
根据1)中所述,父子进程共享代码空间,因此二者代码相同。又根据1)中所述,二者数据空间相互独立,根据fork在父进程与子进程的返回值的不同,父子进程将会执行不同的代码段,从而实现不同的功能。
4)特别重要的一点:fork是把进程当前的情况拷贝一份。切记是当前的情况拷贝一份,而不是代码中原始数据的拷贝。这一点通过下面的代码最能体现。
#include <unistd.h> #include <stdio.h>
int main(void)
{
int i=0;
printf("i son/pa ppid pid fpid\n");
//ppid指当前进程的父进程pid
//pid指当前进程的pid,
//fpid指fork返回给当前进程的值
for(i=0;i<2;i++){
pid_t fpid=fork();
if(fpid==0)
printf("%d child %4d %4d %4d\n",i,getppid(),getpid(),fpid);
else
printf("%d parent %4d %4d %4d\n",i,getppid(),getpid(),fpid);
}
return 0;
}
其运行结果
i son/pa ppid pid fpid
0 parent 3317 4096 4097
1 parent 3317 4096 4098
1 child 1 4098 0
0 child 1 4097 0
1 parent 1 4097 4099
1 child 1 4099 0
之所以运行结果的顺序与http://blog.csdn.net/jason314/article/details/5640969 文中不同,我想就是因为这两个进程执行没有固定的先后顺序,哪个进程先执行要看系统的进程调度策略。
3.总结:
fork()函数通过系统调用创建了一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事(因为共享代码空间),但是由于fork函数的返回值的不同,会产生不同的功能(fork返回值不同,会去执行不同代码段,又因为数据空间是相互独立,故数据互不影响)。
重点记住两点:1)共享程序空间,数据空间相互独立
2)父子进程执行没有固定的先后顺序,哪个进程先执行要看系统的进程调度策略。
相关文章 http://blog.csdn.net/jason314/article/details/5640969
http://blog.csdn.net/dog_in_yellow/article/details/2041079
http://xuzhigang921.blog.163.com/blog/static/56199220201123122639986/
http://coolshell.cn/articles/7965.html 一个fork的面试题
- 基础文章3:进程基础之fork函数
- 【Linux基础】fork函数
- Python基础(七)系统编程之进程-fork
- 进程-3:fork()函数
- 进程控制之fork函数
- linux进程之fork函数
- 进程管理之fork函数
- Linux基础(二)fork()进程
- Linux基础(三)fork()进程
- 进程控制------基础、fork、exec、system
- fork 基础
- 基础文章7:chap15 进程通信之管道 补充
- Linux基础学习系列:对于fork()函数的学习,及进程创建相关知识
- 零基础学习linux中的fork()函数
- c语言基础函数——fork()
- Linux多进程之fork()函数
- 进程通信之(fork函数)
- Linux -- 进程管理之fork() 函数
- 事件处理机制之epoll
- Struts 2 学习笔记 - 4.配置文件深入(2):action,result,exception
- 我的职业规划
- NAND flash和NOR flash的区别详解
- 开源 免费 java CMS - FreeCMS-标签 channelList
- 基础文章3:进程基础之fork函数
- Windows XP/2003 系统进程速查表
- 基础文章4:进程详细描述
- 怎样获取未知DLL的接口参数
- 堆和堆栈
- 程显峰:写一份好简历
- STL algorithm之binary_search
- jquery 如何得到table得到鼠标所在 行号 列号
- Android 2.3.3 以上ProGuard文件详解