http://blog.youkuaiyun.com/tigerjb/article/details/6006884
通过
一前言:
通过原理知识的学习,我们知道每个进程由进程ID号标识。进程被创建时系统会为其分配一个唯一的进程ID号。当一个进程向其父进程(创建该进程的进程)传递其终止消息时,意味这个进程的整个生命周期结束。此时,该进程占用的所用资源包括进程ID被全部释放。
那么在Linux中如何创建一个进程呢?
创建进程有两种方式:一是由操作系统创建,二是由父进程创建的进程(通常为子进程)。
系统调用fork是创建一个新进程的唯一方式。vfork也可创建进程,但它实际上还是调用了fork函数。
Tiger-John说明:
1.由操作系统创建的进程它们之间是平等的不存在资源继承关系。
2.由父进程创建的进程通常为子进程它们之间有继承关系。
3.
如0号idle进程,它是从无到有诞生的第一个线程,主要用于节能
1号进程(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()函数创建一个进程:
程序经过调试后结果如下:
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
从程序执行结果可以看出:
Tiger-John说明:
1>
2>有人说调用fork函数后,fork()函数返回了两个值,这是一中错误的说法。其实,当系统调用fork()函数后
3>.看一个函数实例来仔细体会一下系统调用fork()函数后是如何执行的。
程序经过调试后结果
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>
2>在说明他们的区别之前我们先看两个程序和执行结果
函数实例1:用fork()函数创建进程
3
程序经过调试后;
think@ubuntu:~/work/process_thread/fork3$./fork
fork is different with vfork
Parent process is running
Child process is running
Child process is running
Parent process is running
Child process is running
Parent process is running
Child's globVar = 8,var = 4
Parent process is running
Parent process is running
Parent's globVar = 10,var = 6
函数实例2:用vfork()函数创建一个进程
23
think@ubuntu:~/work/process_thread/fork3$./vfork
fork is different with vfork!
Child process is running
Child process is running
Child process is running
Child's globVar = 8,var = 4
Parent process is running
Parent process is running
Parent process is running
Parent process is running
Parent process is running
Parent's globVar = 13,var = 5
Tiger-John说明:
我们通过以上两个函数的执行可以看到一些区别:
1.
2.
通过以上程序的运行结果可以证明
3.
--------------------------------------------
1.用vfork()函数创建子进程后,父进程中globVar和var最后均递增了8.这是因为vfork的子进程共享父进程的地址空间,子进程修改变量对父进程是可见的。
2.使用vfork()函数子进程后打印的结果是子进程在前,父进程在后,说明vfork()保证子进程先执行,在子进程调用exit获exec之前父进程处于阻塞等待状态。
3>那么现在来看看fork()和vfork()函数之间的区别:
(1)fork():使用fork()创建一个子进程时,子进程只是完全复制父进程的资源。这样得到的子进程独立于父进程具有良好的并发性。(2)fork():父子进程执行顺序不定;
vfork():保证子进程先运行,在调用exec或exit之前与父进程共享数据,在它调用exec或exit之后父进程才可能被调度运行。
(3)vfork保证子进程先运行,在它调用exec或exit后父进程才可能被调度运行。如果在调用这两个函数之前子进程依赖于父进程的进一步动作,则会导致死锁。