Linux进程(三):进程的创建


fork

​   fork用来创建一个进程,当我们的进程执行到了fork的时候,系统将为我们复制一份进程资源,并且两个进程都将从fork函数返回。

​   从内核的调度层面来说,只要一个进程存在task_struct,那么该进程就可以被调度。所以在我们的父进程把子进程fork出来的时刻,父进程会将该进程内的资源拷贝给子进程。

在这里插入图片描述

​   当一个进程刚刚被创建出来的时候执行的是一个copy,但是任何秀海都将造成父子进程资源的分类,如:chrootopen、写memorymmapsigaction等。

​   task_struct中,文件资源、信号资源等资源的分裂都比较好实现,唯一困难的就是内存资源的分裂,因为我们需要探测是谁在写哪一块内存内容,且对于fork来讲,有一个很讨厌的东西叫exec系列的系统调用,它会勾引子进程另起炉灶。如果创建子进程就要内存拷贝的的话,一执行exec,辛辛苦苦拷贝的内存又被完全放弃了。由于fork()后会产生一个和父进程完全相同的子进程,但子进程在此后多会exec系统调用,处于效率考虑,linux中引入了“写时复制技术-Copy-On-Write”。接下来就是内存资源分裂的写时分裂技术。

copy-on-write(COW)

在这里插入图片描述

​   在最开始时,父进程的虚拟地址为virt1,物理地址为phy1,此时进程根据MMU可通过虚拟地址查询到物理地址并且获取内存中的数据。且当前内存数据段的权限为R+W

​   当父进程通过fork创建出子进程时,此时子进程的虚拟地址以及物理地址都和父进程的相同,但是Linux将页表当中这一页所对应的访问权限变成了RD-ONLY只读权限。

​   若子进程或父进程在某个需要修改内存中的数据时,CPU一旦往一块RD-ONLY权限的内存页中写数据,将会收到一个page fault(缺页中断)。假设此刻子进程需要向这块内存中写入数据,CPU收到中断之后将分配一块新的物理内存给子进程,此时子进程将得到一片新的物理地址(如上图中的phy2),然后Linux内核会将之前的phy1中的内容拷贝到phy2中去,然后修改子进程的页表,使得子进程的虚拟地址virt1指向新的物理地址phy2此时,父子进程的虚拟地址都是相同的,但指向的物理地址则是各自不同的。

​   在此之后,Linux内核将两个进程的页表的访问权限都改成R+W,父子进程实现内存分裂。

​   copy-on-write技术严重依赖于CPU中的MMU(memory management unit)。若CPU中没有MMU,则fork是不能工作的。

​   在Linux2.6之前(2.6版本之后Linux系统支持了无MMU的CPU),在没有MMU的CPU中是不可能执行copy-on-write的,所以在这样的CPU中去跑Linux时是没有fork的,只有vfork

vfork

​   vforkfork的其中一点区别主要在于**vfork在调用之后将阻塞父进程,直到子进程调用_exitexec这两个系统调用。**同时vforkfork还有一点区别:内存分裂技术不同。

​   在执行vfork时,父进程的mm_struct不再对拷给子进程,而是子进程的task_struct中的mm指针直接指向父进程mm_struct指向的结构体。

在这里插入图片描述

可用以下代码做一个小测试:

int data = 10;

int child_process()
{
	printf("Child process %d, data %d\n",getpid(),data);
    //注意:执行data=20这行代码的代价时Linux内核其实是做了一系列操作:
    //首先,由于此块内存时只读的,所以将发生缺页中断
    //发生缺页中断后Linux内核将申请一块新的内存
    //申请完内存后内核把该进程的虚拟地址指向新的物理地址,并把老的物理页中的内容拷贝到新的物理页中
    //拷完之后Linux把父子进程中的内存访问权限都改为R+W,并把pc指针再次指向data=20执行
	data = 20;
	printf("Child process %d, data %d\n",getpid(),data);
	_exit(0);
}

int main(int argc, char* argv[])
{
	if(vfork()==0) {
		child_process();	
	}
	else{
		sleep(1);
		printf("Parent process %d, data %d\n",getpid(), data);
	}
}

  这个程序的输出为:

在这里插入图片描述

在此处,vfork相当于clone函数将flags标志设置为CLONE_VMCLONE_VFORK,接下来我们就介绍更加强大的函数:clone

clone

​   clone是Linux为创建线程设计的(虽然也可以用clone创建进程)。所以可以说clone是fork的升级版本,不仅可以创建进程或者线程,还可以指定创建新的命名空间(namespace)、有选择的继承父进程的内存、甚至可以将创建出来的进程变成父进程的兄弟进程等等。

​   clone函数功能强大,带了众多参数,它提供了一个非常灵活自由的常见进程的方法。因此由他创建的进程要比前面2种方法要复杂。clone可以让你有选择性的继承父进程的资源,你可以选择想vfork一样和父进程共享一个虚存空间,从而使创造的是线程,你也可以不和父进程共享,你甚至可以选择创造出来的进程和父进程不再是父子关系,而是兄弟关系。先有必要说下这个函数的结构:

int clone(int (*fn)(void*), void *child_stack, int flags, void *arg);

fn为函数指针,此指针指向一个函数体,即想要创建进程的静态程序(我们知道进程的4要素,这个就是指向程序的指针,就是所谓的“剧本", );

`child_stack`为给子进程分配系统堆栈的指针(在linux下系统堆栈空间是2页面,就是8K的内存,其中在这块内存中,低地址上放入了值,这个值就是进程控制块`task_struct`的值);

arg就是传给子进程的参数一般为(0);

flags为要复制资源的标志,描述你需要从父进程继承那些资源(是资源复制还是共享,在这里设置参数:

下面是flags可以取的值:

参数标志含义
CLONE_PARENT创建的子进程的父进程是调用者的父进程,新进程与创建它的进程成了“兄弟”而不是“父子”
CLONE_FS子进程与父进程共享相同的文件系统,包括root、当前目录、umask
CLONE_FILES子进程与父进程共享相同的文件描述符(file descriptor)表
CLONE_NEWNS为子进程创建新的命名空间
CLONE_SIGHAND子进程与父进程共享相同的信号处理(signal handler)表
CLONE_PTRACE若父进程被trace,子进程也被trace,继续调试子进程
CLONE_VFORK父进程被挂起,直至子进程释放虚拟内存资源
CLONE_VM子进程与父进程运行于相同的内存空间
CLONE_PID子进程在创建时PID与父进程一致
CLONE_THREADLinux 2.4中增加以支持POSIX线程标准,子进程与父进程共享相同的线程群
CLONE_IDLETASKPID设置为0(只供idle进程使用)
CLONE_SETTID将TID会写至用户空间
CLONE_SITTLS为子进程创建新的TLS
CLONE_SYSVSEM父子进程共享System V SEM_UNDO语义
CLONE_UNTRACE防止跟踪进程在子进程上强制执行CLONE_PTRACE
CLONE_STOPTASK_STOPPED状态开始子进程

​   当我们使用pthread_create创建线程时,本质上也是通过调用Linux系统中的clone()函数,但此时pthread_create函数调用clone时会将子进程的各种资源指针全部设为和父进程相同的指针:

clone(CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, 0)

​   上面的代码产生的结果和调用fork()差不多,只是父子俩共享地址空间、文件系统资源、文件描述符和信号处理程序。换个说法就是,新建的进程和它的父进程就是流行的所谓线程。这种方式其实就是LWP的实现。

clone, fork, vfork区别与联系

  系统调用服务例程sys_clonesys_forksys_vfork三者最终都是调用do_fork函数完成.

  do_fork的参数与clone系统调用的参数类似, 不过多了一个regs(内核栈保存的用户模式寄存器). 实际上其他的参数也都是用regs取的。

  三者具体调用do_fork时的参数不同。

referfence

http://blog.csdn.net/gogokongyin/article/details/51334773

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值