进程学习笔记

转自 https://www.cnblogs.com/jackl...

  • 进程控制块(PCB)

============

在Linux中task_struct结构体即是PCB。PCB是进程的唯一标识,PCB由链表实现(为了动态插入和删除)。
进程创建时,为该进程生成一个PCB;进程终止时,回收PCB。
PCB包含信息:1、进程状态(state);2、进程标识信息(uid、gid);3、定时器(time);4、用户可见寄存器、控制状态寄存器、栈指针等(tss)
每个进程都有一个非负的唯一进程ID(PID)。虽然是唯一的,但是PID可以重用,当一个进程终止后,其他进程就可以使用它的PID了。
PID为0的进程为调度进程,该进程是内核的一部分,也称为系统进程;PID为1的进程为init进程,它是一个普通的用户进程,但是以超级用户特权运行;PID为2的进程是页守护进程,负责支持虚拟存储系统的分页操作。除了PID,每个进程还有一些其他的标识符:

#if defined __USE_XOPEN_EXTENDED || defined __USE_XOPEN2K8/* Return the session ID of the given process.  */extern __pid_t getsid (__pid_t __pid) __THROW;#endif/* Get the real user ID of the calling process.  */extern __uid_t getuid (void) __THROW;/* Get the effective user ID of the calling process.  */extern __uid_t geteuid (void) __THROW;/* Get the real group ID of the calling process.  */extern __gid_t getgid (void) __THROW;/* Get the effective group ID of the calling process.  */extern __gid_t getegid (void) __THROW;

五种进程之间转换关系如图:

每个进程的task_struct和系统空间堆栈存放位置如下:两个连续的物理页【《Linux内核源代码情景分析》271页】


系统堆栈空间不能动态扩展,在设计内核、驱动程序时要避免函数嵌套太深,同时不宜使用太大太多的局部变量,因为局部变量都是存在堆栈中的。

进程的创建

新进程的创建,首先在内存中为新进程创建一个task_struct结构,然后将父进程的task_struct内容复制其中,再修改部分数据。分配新的内核堆栈、新的PID、再将task_struct 这个node添加到链表中。所谓创建,实际上是“复制”。

子进程刚开始,内核并没有为它分配物理内存,而是以只读的方式共享父进程内存,只有当子进程写时,才复制。即“copy-on-write”。
fork都是由do_fork实现的,do_fork的简化流程如下图:

fork函数

#include<unistd.h>pid_t fork(void)    //子进程返回0,父进程返回子进程ID,出错返回-1.

fork函数时调用一次,返回两次。在父进程和子进程中各调用一次。子进程中返回值为0,父进程中返回值为子进程的PID。程序员可以根据返回值的不同让父进程和子进程执行不同的代码。
一个形象的过程: