Linux进程学习(二)之fork()和vfork()的学习
2012-07-04 15:53
831 查看
http://blog.csdn.net/tigerjb/article/details/6006884
fork()和vfork()的学习
通过 上一部分的学习,我们了解了进程的概念以及在Linux中进程的实现,此部分我们将具体学习如何在Linux中创建一个进程。
一前言:
通过原理知识的学习,我们知道每个进程由进程ID号标识。进程被创建时系统会为其分配一个唯一的进程ID号。当一个进程向其父进程(创建该进程的进程)传递其终止消息时,意味这个进程的整个生命周期结束。此时,该进程占用的所用资源包括进程ID被全部释放。
那么在Linux中如何创建一个进程呢?
创建进程有两种方式:一是由操作系统创建,二是由父进程创建的进程(通常为子进程)。
系统调用fork是创建一个新进程的唯一方式。vfork也可创建进程,但它实际上还是调用了fork函数。
Tiger-John说明:
1.由操作系统创建的进程它们之间是平等的不存在资源继承关系。
2.由父进程创建的进程通常为子进程它们之间有继承关系。
3. 在系统启动时,OS会创建一些进程,它们承担着管理和分配系统资源的任务,即系统进程。
如0号idle进程,它是从无到有诞生的第一个线程,主要用于节能 ;关于 idle进程 , 系统最初引导 0号进程,对应的 PCB为 init_task(),要说明下它是0号进程 PCB的头,并不是 1号 init进程,在引导结束后即成为 cpu 上的 idle进程。在每个 cpu上都有一个 idle进程,这些进程登记在 init_tasks[]数组中。 idle进程不进入就绪队列,系统稳定后,仅当就绪队列为空的时候 idle 进程才会被调度到,在没有其它进程运行的情况下,它大量时间占用 cpu 。
1号进程(init进程)它是一个由内核启动的用户级进程 ,它是所有用户进程的父进程。实际上,Linux2.6在初始化阶段首先把它建立为一个内核线程kernel_init:
kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
参数CLONE_FS | CLONE_FILES |CLONE_SIGHAND表示0号线程和1号线程分别共享文件系统(CLONE_FS)、打开的文件(CLONE_FILES)和信号处理程序(CLONE_SIGHAND)。当调度程序选择到kernel_init内核线程时,kernel_init就开始执行内核的一些初始化函数将系统初始化。
那么,kernel_init()内核线程是怎样变为用户进程的呢?
实际上,kernel_init()内核函数中调用了execve()系统调用,该系统调用装入用户态下的可执行程序init(/sbin/init)。注意,内核函数kernel_init()和用户态下的可执行文件init是不同的代码,处于不同的位置,也运行在不同的状态,因此,init是内核线程启动起来的一个普通的进程,这也是用户态下的第一个进程。init进程从不终止,因为它创建和监控操作系统外层所有进程的活动。
二fork()函数和vfork()函数的学习
1.fork()函数
调用fork函数后,当前进程分裂为两个进程,一个是原来的父进程,另一个是刚创建的子进程。父进程调用fork后返回值是子进程的ID,子进程中返回值是0,若进程创建失败,只返回-1。失败原因一般是父进程拥有的子进程个数超过了规定限制(返回EAGAIN)或者内存不足(返回ENOMEM)。我们可以依据返回值判断进程,一般情况下调用fork函数后父子进程谁先执行是未定的,取决于内核所使用的调度算法。一般情况下os让所有进程享有同等执行权,除非某些进程优先级高。若有一个孤儿进程,即父进程先于子进程死去,子进程将会由init进程收养。
函数实例:通过fork()函数创建一个进程:
1#include<sys/types.h>
2#include<unistd.h>
3#include<stdio.h>
4
5 main()
6 {
7 pid_t
pid;
8 printf("PID
before fork() :%d/n",(int)getpid());
9
10 pid
= fork();
11 if(pid
< 0){
12 printf("error
in fork!/n");
13 }
14 else
if(0 == pid){
15 printf("I'm
the child process, CurpPID is %d,ParentPid is%d /n",pid,(int)getppid());
16 }
17 else{
18 printf("I'm
the parent process,child PID is %d,ParentPIDis %d/n",pid,(int)getpid());
19 }
20
程序经过调试后结果如下:
think@ubuntu:~/work/process_thread/fork$./fork
PID before fork() :4566
I'm the parent process,child PID is 4567,ParentPID is 4566
I'm the child process, CurpPID is 0,ParentPid is 4566
从程序执行结果可以看出: 调后fork()函数后返回两个值,子进程返回值为0,而父进程的返回值为创建的子进程的进程ID。
Tiger-John说明:
1> Linux进程一般包括代码段,数据段和堆栈段。代码段存放程序的可执行代码;数据段存放程序的全局变量、常量、静态变量;堆存放动态分配的内存变量,栈用于函数调用,存放函数参数、函数内部定义的局部变量。
2>有人说调用fork函数后,fork()函数返回了两个值,这是一中错误的说法。其实,当系统调用fork()函数后 fork()会将调用进程的所有内容原封不动的拷贝到新产生的子进程中去, 当前进程分裂成了两个进程分别在执行,互不干扰。
3>.看一个函数实例来仔细体会一下系统调用fork()函数后是如何执行的。
1#include<stdio.h>
2#include<unistd.h>
3#include<sys/types.h>
4
5 int main()
6 {
7 pid_t
pid;
8 int
count = 0;
9 pid
= fork();
10
11 printf("This
is first time,pid = %d/n",pid);
12 printf("This
is the second time,pid = %d/n",pid);
13 count++;
14 printf("count
= %d/n",count);
15
16 if(pid
> 0){
17 printf("This
is the parent process,the child has the pid:%d /n",pid);
18 }
19 else
if(!pid){
20 printf("This
is the child process./n");
21 }
22 else{
23 printf("fork
failed./n");
24 }
25
26 printf("This
is third,pid = %d/n",pid);
27 printf("This
is four time,pid = %d/n",pid);
28 return
0;
29 }
程序经过调试后结果
think@ubuntu:~/work/process_thread/fork1$./fork
This is first time,pid = 4614
This is the second time,pid = 4614
count = 1
This is the parent process,the child has the pid :4614
This is third,pid = 4614
This is four time,pid = 4614
This is first time,pid = 0
This is the second time,pid = 0
count = 1
This is the child process.
This is third,pid = 0
This is four time,pid = 0
think@ubuntu:~/work/process_thread/fork1$
Tiger-John说明:
从上面的程序的执行结果我们看到一个奇怪的现象:为什么printf的语句执行两次,
而那句“count++;”的语句却只执行了一次 ?
系统在调用fork()后分裂成了两个函数分别执行 ,互不干扰 。
2.Vfork和fork的区别:
1> vfork也可创建进程,但它实际上还是调用了fork函数。
2>在说明他们的区别之前我们先看两个程序和执行结果
函数实例1:用fork()函数创建进程
1#include<stdio.h>
2#include<sys/types.h>
3#include<unistd.h>
4#include<stdlib.h>
5 int globVar = 5;
6
7 int main(void)
8 {
9 pid_t
pid;
10 int
var = 1;
11 int
i;
12 printf("fork
is different with vfork /n");
13
14 pid
= fork();
15 if(!pid){
16 i=3;
17 while(i--
> 0){
18 printf("Child
process is running/n");
19 globVar++;
20 var++;
21 sleep(1);
22 }
3
fork()和vfork()的学习
通过 上一部分的学习,我们了解了进程的概念以及在Linux中进程的实现,此部分我们将具体学习如何在Linux中创建一个进程。
一前言:
通过原理知识的学习,我们知道每个进程由进程ID号标识。进程被创建时系统会为其分配一个唯一的进程ID号。当一个进程向其父进程(创建该进程的进程)传递其终止消息时,意味这个进程的整个生命周期结束。此时,该进程占用的所用资源包括进程ID被全部释放。
那么在Linux中如何创建一个进程呢?
创建进程有两种方式:一是由操作系统创建,二是由父进程创建的进程(通常为子进程)。
系统调用fork是创建一个新进程的唯一方式。vfork也可创建进程,但它实际上还是调用了fork函数。
Tiger-John说明:
1.由操作系统创建的进程它们之间是平等的不存在资源继承关系。
2.由父进程创建的进程通常为子进程它们之间有继承关系。
3. 在系统启动时,OS会创建一些进程,它们承担着管理和分配系统资源的任务,即系统进程。
如0号idle进程,它是从无到有诞生的第一个线程,主要用于节能 ;关于 idle进程 , 系统最初引导 0号进程,对应的 PCB为 init_task(),要说明下它是0号进程 PCB的头,并不是 1号 init进程,在引导结束后即成为 cpu 上的 idle进程。在每个 cpu上都有一个 idle进程,这些进程登记在 init_tasks[]数组中。 idle进程不进入就绪队列,系统稳定后,仅当就绪队列为空的时候 idle 进程才会被调度到,在没有其它进程运行的情况下,它大量时间占用 cpu 。
1号进程(init进程)它是一个由内核启动的用户级进程 ,它是所有用户进程的父进程。实际上,Linux2.6在初始化阶段首先把它建立为一个内核线程kernel_init:
kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
参数CLONE_FS | CLONE_FILES |CLONE_SIGHAND表示0号线程和1号线程分别共享文件系统(CLONE_FS)、打开的文件(CLONE_FILES)和信号处理程序(CLONE_SIGHAND)。当调度程序选择到kernel_init内核线程时,kernel_init就开始执行内核的一些初始化函数将系统初始化。
那么,kernel_init()内核线程是怎样变为用户进程的呢?
实际上,kernel_init()内核函数中调用了execve()系统调用,该系统调用装入用户态下的可执行程序init(/sbin/init)。注意,内核函数kernel_init()和用户态下的可执行文件init是不同的代码,处于不同的位置,也运行在不同的状态,因此,init是内核线程启动起来的一个普通的进程,这也是用户态下的第一个进程。init进程从不终止,因为它创建和监控操作系统外层所有进程的活动。
二fork()函数和vfork()函数的学习
1.fork()函数
调用fork函数后,当前进程分裂为两个进程,一个是原来的父进程,另一个是刚创建的子进程。父进程调用fork后返回值是子进程的ID,子进程中返回值是0,若进程创建失败,只返回-1。失败原因一般是父进程拥有的子进程个数超过了规定限制(返回EAGAIN)或者内存不足(返回ENOMEM)。我们可以依据返回值判断进程,一般情况下调用fork函数后父子进程谁先执行是未定的,取决于内核所使用的调度算法。一般情况下os让所有进程享有同等执行权,除非某些进程优先级高。若有一个孤儿进程,即父进程先于子进程死去,子进程将会由init进程收养。
函数实例:通过fork()函数创建一个进程:
1#include<sys/types.h>
2#include<unistd.h>
3#include<stdio.h>
4
5 main()
6 {
7 pid_t
pid;
8 printf("PID
before fork() :%d/n",(int)getpid());
9
10 pid
= fork();
11 if(pid
< 0){
12 printf("error
in fork!/n");
13 }
14 else
if(0 == pid){
15 printf("I'm
the child process, CurpPID is %d,ParentPid is%d /n",pid,(int)getppid());
16 }
17 else{
18 printf("I'm
the parent process,child PID is %d,ParentPIDis %d/n",pid,(int)getpid());
19 }
20
程序经过调试后结果如下:
think@ubuntu:~/work/process_thread/fork$./fork
PID before fork() :4566
I'm the parent process,child PID is 4567,ParentPID is 4566
I'm the child process, CurpPID is 0,ParentPid is 4566
从程序执行结果可以看出: 调后fork()函数后返回两个值,子进程返回值为0,而父进程的返回值为创建的子进程的进程ID。
Tiger-John说明:
1> Linux进程一般包括代码段,数据段和堆栈段。代码段存放程序的可执行代码;数据段存放程序的全局变量、常量、静态变量;堆存放动态分配的内存变量,栈用于函数调用,存放函数参数、函数内部定义的局部变量。
2>有人说调用fork函数后,fork()函数返回了两个值,这是一中错误的说法。其实,当系统调用fork()函数后 fork()会将调用进程的所有内容原封不动的拷贝到新产生的子进程中去, 当前进程分裂成了两个进程分别在执行,互不干扰。
3>.看一个函数实例来仔细体会一下系统调用fork()函数后是如何执行的。
1#include<stdio.h>
2#include<unistd.h>
3#include<sys/types.h>
4
5 int main()
6 {
7 pid_t
pid;
8 int
count = 0;
9 pid
= fork();
10
11 printf("This
is first time,pid = %d/n",pid);
12 printf("This
is the second time,pid = %d/n",pid);
13 count++;
14 printf("count
= %d/n",count);
15
16 if(pid
> 0){
17 printf("This
is the parent process,the child has the pid:%d /n",pid);
18 }
19 else
if(!pid){
20 printf("This
is the child process./n");
21 }
22 else{
23 printf("fork
failed./n");
24 }
25
26 printf("This
is third,pid = %d/n",pid);
27 printf("This
is four time,pid = %d/n",pid);
28 return
0;
29 }
程序经过调试后结果
think@ubuntu:~/work/process_thread/fork1$./fork
This is first time,pid = 4614
This is the second time,pid = 4614
count = 1
This is the parent process,the child has the pid :4614
This is third,pid = 4614
This is four time,pid = 4614
This is first time,pid = 0
This is the second time,pid = 0
count = 1
This is the child process.
This is third,pid = 0
This is four time,pid = 0
think@ubuntu:~/work/process_thread/fork1$
Tiger-John说明:
从上面的程序的执行结果我们看到一个奇怪的现象:为什么printf的语句执行两次,
而那句“count++;”的语句却只执行了一次 ?
系统在调用fork()后分裂成了两个函数分别执行 ,互不干扰 。
2.Vfork和fork的区别:
1> vfork也可创建进程,但它实际上还是调用了fork函数。
2>在说明他们的区别之前我们先看两个程序和执行结果
函数实例1:用fork()函数创建进程
1#include<stdio.h>
2#include<sys/types.h>
3#include<unistd.h>
4#include<stdlib.h>
5 int globVar = 5;
6
7 int main(void)
8 {
9 pid_t
pid;
10 int
var = 1;
11 int
i;
12 printf("fork
is different with vfork /n");
13
14 pid
= fork();
15 if(!pid){
16 i=3;
17 while(i--
> 0){
18 printf("Child
process is running/n");
19 globVar++;
20 var++;
21 sleep(1);
22 }
3
相关文章推荐
- Linux的进程学习笔记之fork与vfork
- Linux学习之进程fork()与vfork()
- linux学习---进程控制(fork,vfork,popen,exec,system)
- Linux进程学习---fork()和vfork()
- 【经典转载】Linux进程学习系列之二 fork()和vfork()的学习
- linux进程系列(1)进程创建fork、vfork
- 进程学习(一)——fork()和vfork()函数学习过程
- Linux进程创建fork()与vfork()
- Linux进程创建:fork,vfork,exec,clone总结
- linux 进程学习体会——fork()
- linux进程之fork vs vfork
- linux学习-进程创建(fork,wait,waitpid)
- Linux基础学习系列:对于fork()函数的学习,及进程创建相关知识
- linux中建立新的进程-fork、vfork、clone解析
- Linux基础学习系列:对于fork()函数的学习,及进程创建相关知识
- Linux下fork()&vfork()的区别、getenv()&setenv()函数以及僵尸进程、孤儿进程讲解
- Linux进程fork,exec,vfork详解
- 【Linux】进程的创建fork()和vfork()
- linux进程创建过程与原理 fork,vfork,clone的区别
- .linux进程知识 程序存储、crontab、fork与vfork、exec、_exit()、wait()与waitpid()、孤儿和僵尸 文件读写 文件锁、select、poll