目录
一、进程创建
(1)fork函数
函数原型:Pid_t fork(void);//系统调用函数
出错返回-1;
成功 调用一次返回两次;
Fork()函数会新生成一个进程,调用fork函数的进程为父进程,新生成的进程为子进程。Fork调用一次返回两次,在父进程返回子进程的pid(pid肯定不为0),在子进程返回0,失败返回-1。
(2)写时拷贝技术
由于fork之后经常跟随exec,在这里用到了写时拷贝技术。Fork之后,子进程会拷贝父进程的PCB结构,然后对PCB里边的数据做修改。父进程的页表直接拷贝给子进程。父子进程共享所有的数据空间(开始时)。这些区域由父子进程共享,而且内核将他们的访问权限都改为只读的。如果父子进程任意一方视图修改这些区域,则内核只为修改区域的那块内存制作一个副本,通常是虚拟存储器系统中的一“页”。Fork之后,父子进程相互独立。Fork之前打开的文件描述符,父子进程共享fork之前打开文件的读写偏移量。
在此之后,父子进程,并不共享全局数据,堆区数据和栈区数据。
Fork时,子进程的PCB是由父进程拷贝(浅拷贝)而来,父子进程共享fork之前打开的文件。
(3)frok之后谁先运行?
子进程从fork()之后开始执行;子进程继承父进程的一些状态;fork()之后,父子进程谁先运行由操作系统决定,且父子进程是并发执行;
(4)fork创建进程的流程,其内核实现原理
Linux通过clone系统调用实现fork()。这个调用通过一系列的参数标志来指明父、子进程需要共享的资源、fork、vfork和_clone库函数都根据各自需要的参数标志去调用clone。然后由clone去调用do_fork。
Do_fork完成了创建中的大部分工作,它的定义是在kernel/fork.c文件中,该函数调用copy_process()函数,然后让程序开始运行。Copy_process完成的工作:
①调用dup_task_struct()为新进程创建一个内核栈、thread_info结构和task_struct,这些值与当前进程的值相同。此时,子进程和父进程的描述符是完全相同的。
②检查新创建的这个紫禁城后,当前用户所拥有的进程数目没有超出给他分配的资源的限制。
③现在,子进程着手使自己与父进程区别开进程描述符内的许多成员都要被清0或者设为初始值。 进程描述符的成员值并不是继承而来的,而主要是统计信息。进程描述符中的大多数数据都是共享的。
④接下来,子进程的状态被设置为TASK_UNINTERRUPTIBLE以保证它不会投入运行。
⑤copy_process()调用copy_flags()以更新task_struct的flags成员。表明进程是