Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1308847
  • 博文数量: 213
  • 博客积分: 7590
  • 博客等级: 少将
  • 技术积分: 2185
  • 用 户 组: 普通用户
  • 注册时间: 2008-08-31 17:31
个人简介

热爱开源,热爱linux

文章分类

全部博文(213)

文章存档

2018年(4)

2017年(1)

2015年(1)

2014年(5)

2013年(2)

2012年(2)

2011年(21)

2010年(82)

2009年(72)

2008年(23)

分类: LINUX

2009-08-13 11:26:53


一、进程的创建步骤以及创建函数的介绍

1、使用fork()或者vfork()函数创建新的进程

2、条用exec函数族修改创建的进程。使用fork()创建出来的进程是当前进程的完全复制,然而我们创建进程是为了让新的进程去执行新的程序,因此,就需要用到exec函数族对创建出来的新进程进行修改,让他拥有和父进程不一样的东西,修改后就可以执行新的程序,当然,修改后的子进程包含了要执行程序的信息。

Linux中,fork()vfork()就是用于创建进程的两个函数,他们的相关信息如下:

创建进程函数:

pid_t fork(void)//成功返回0,失败返回-1

fork()用于创建新的进程,所创建进程为当前进程的子进程,可以通过fork()函数的返回质6来控制进程是在父进程中还是在子进程中。如果运行在父进程中,则返回PID为子进程的进程号,如果在子进程中,则返回的PID0

pid_t vfork(void)//成功返回0,失败返回-1

vfork()函数和fork()函数比较类似,都用于创建子进程。只是其用于创建新的进程,父子进程共享虚拟内存空间。然而在内核中,vfork()的实现任然调用fork()函数,调用函数如下:

sys_vfork(struct pt_regs *regs)
{
        return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->gr[30], regs, 0, NULL, NULL);
}


在上述函数中,pid_t为隐含类型,实际上就是一个int的类型。隐含类型只数据类型的物理表示是未知的或者是不相关的

二、实现过程和区别

1Linux是通过_cloen()系统调用来实现fork()的,这一调用通过一系列的参数标志来指明父子进程需要的资源。Fork(),vfork(),_cloen()库函数都根据各自需要的参数标志去调用cloen(),然后由cloen()去调用do_fork()函数,do_fork()函数也就是真正的创建进程的函数。他完成了创建进程的大部分工作。同时他还会调用copy_process()函数。然后让进程开始运行。

2vfork()fork()的功能相同,除了不拷贝父进程的页表项,也就是说不会复制和父进程相关的资源,父子进程将共享地址空间,子进程对虚拟内存空间的任何实际修改实际上是在修改父进程虚拟内粗空间的内容。并且其父进程会被阻塞,直到子进程退出或者执行exec()函数族.这样由于父子进程共享地址空间,避免了fork在资源复制是的消耗。

3、写时copy机制:Linux系统采用了“些操作时复制”的方法,其是一种延迟资源复制的方法,子进程在创建的时候并不复制父进程的相关资源,父子进程通过访问相同的物理内存来伪装已经实现了的对资源的复制。这种共享是制度方式是只读方式,这一点与vfork是不同的,当子进程对内存数据存在这些的操作时,才会进香资源的复制。正是由于这种机制的出现,vfork()好像已经没有什么作用了。

三、在进程窗创建过程中copy_process()函数完成的工作//摘自:Linux内核设计与实现

1、调用dup_task_struct()为心进程创建一个内核栈、thread_info结构和task_struct,这些值与当前进程的值相同。此时,子进程和父进程的描述符完全相同。

2、检查新创建的这个子进程后,当前用户所用有的进程数目没有超过给他分配的资源的限制

3、现在,子进程着手使自己与父进程区别开来,进程描述符内的许多成员都要被清0或者设置初始值。进程描述符的成员值并不是继承而来的,而主要是统计信息,进程描述符中的大多数数据都是共享的。

4、接下来,子进程的状态被设置为不可终端等待状态以保证他不会投入运行

5copy_process()调用copy_flags()以更新task_structflags成员。表明进程是拥有超级用户权限的PF_SUPER[RIV标志被清0。表明进程还没有调用exec()函数的PE_FORKNOEXEC标志被设置。

6、调用get_pid()为新进程获取一个有效的PID

7、根据传给cloen()的参数标志copy_process()拷贝或者共享打开的文件、文件系统信、信号处理函数、进程地址空间和命名空间等。

8、让父进程和子进程平分剩余的时间片。

9、最后,copy_proccess()做扫尾工作并返回一个只想子进程的指针。


以下出自http://shichen515.blog.sohu.com/68965577.html

一、fork
1. 调用方法
#include
#include

pid_t fork(void);
正确返回:在父进程中返回子进程的进程号,在子进程中返回0
错误返回:-1

     子进程是父进程的一个拷贝。即,子进程从父进程得到了数据段和堆栈段的拷贝,这些需要分配新的内存;而对于只读的代码段,通常使用共享内存的方式访问。fork返回后,子进程和父进程都从调用fork函数的下一条语句开始执行。
     父进程与子进程的不同之处在于:fork的返回值不同——父进程中的返回值为子进程的进程号,而子进程为0
2. fork函数调用的用途
⑴ 一个进程希望复制自身,从而父子进程能同时执行不同段的代码。
⑵ 进程想执行另外一个程序

二、vfork
1. 调用方法
与fork函数完全相同
#include
#include

pid_t fork(void);
正确返回:在父进程中返回子进程的进程号,在子进程中返回0
错误返回:-1

2. vfork函数调用的用途
       用vfork创建的进程主要目的是用exec函数执行另外的程序,与fork的第二个用途相同

三、fork与vfork的区别
1. fork要拷贝父进程的数据段;而vfork则不需要完全拷贝父进程的数据段,在子进程没有调用exec和exit之前,子进程与父进程共享数据段
2. fork不对父子进程的执行次序进行任何限制;而在vfork调用中,子进程先运行,父进程挂起,直到子进程调用了exec或exit之后,父子进程的执行次序才不再有限制

四、结束子进程
     结束子进程不用exit(0),而使用_exit(0)。这是因为_exit(0)在结束进程时,不对标准I/O流进行任何操作。而exit(0)则会关闭进程的所有标准I/O流。


关于fork()函数的说明:
          1)、子进程返回的ID为0,但并不是它真正的进程ID。真正的ID可以通过getpid()函数获得;
          2)、子进程是父进程的复制品,可以获得父进程的资源(数据空间、堆和栈的拷贝);
          3)、文件共享:由父进程打开的所有描述符都被复制到子进程中,父进程和子进程中每个相同的描述符共享一个文件表项。当父进程的文件位移量发生改变时,子 进程也能得到更新了的文件位移量。文件共享的情况下要采取同步措施,否则,输入输出的顺序就会混乱,还有可能产生死锁;
          4)、子进程还继承父进程的用户ID、组ID、控制终端、当前工作目录、环境、资源限制等等。
fork()函数的两种用法:
          1)、父进程希望复制自己,希望父进程和子进程同时执行不同的代码段;
例如:当父进程收到请求时,父进程让子进程去处理请求,自己去等待下一个请求。
          2)、一个进程要执行不同的程序。
例如:在shell编程中,子进程在从fork()返回后,立即调用exec函数,以执行一个不同的程序

阅读(3147) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~