原创作品转载请注明出处 + https://github.com/mengning/linuxkernel/
学号 271
实验环境:实验楼虚拟,机内核版本Linux3.18.6
一. 进程的创建
1.什么是进程,进程有什么状态?
通俗的讲程序是一个包含可以执行代码的静态的文件。进程是一个开始执行但是还没有结束的程序的实例。当程序被系统调用到内存以后,系统会给程序分配一定的资源(内存,设备等等)然后进行一系列的复杂操作,使程序变成进程以供系统调用。
进程按照功能可以分为内核进程和用户进程
在Linux中进程分为五个状态:。
- task_running:就绪态或者运行态,进程就绪可以运行,但是不一定正在占有CPU
- task_uniterruptible: 睡眠态,深度睡眠,不响应信号,典型场景是进程获取信号量阻塞
- task_interruptible:阻睡眠态,但是进程处于浅度睡眠,可以响应信号,一般是进程主动sleep进入的状态
- task_zobie:僵尸态,进程已退出或者结束,但是父进程还不知道,没有回收时的状态
- task_stoped:停止,调试状态
2.进程的结构
本文以Linux3.18.6内核为基础进行介绍,详细见/linux-3.18.6/include/linux/sched.h:
为了管理进程,OS用PCB(进程描述符)来定义其数据结构在Linux中就是task_struct,由于其定义比较复杂,就选几个比较重要的讲一下:
pid_t pid;//进程ID
volatile long state;//表示进程的当前状态,一共大约有11中,比较常见的见上面的进程状态图
unsigned long flags; //进程标志:
long priority; //进程优先级。 Priority的值给出进程每次获取CPU后可使用的时间(按jiffies计)。优先
//级可通过系统调用sys_setpriorty改变(在kernel/sys.c中)。
long counter; //在轮转法调度时表示进程当前还可运行多久。
unsigned long policy; //该进程的进程调度策略,可以通过系统调用sys_sched_setscheduler()
void *stack;//进程通过alloc_thread_info函数分配它的内核栈,通过free_thread_info函数释放所分配的
//内核栈。
3.进程的创建:
Linux主要提供了fork、vfork和clone三个系统调用来创建一个新进程,在源码中,通过一个系统调用表映射到sys_fork(),sys_vfork(),sys_clone(),再在这三个函数中去调用do_fork()去做具体的创建进程工作。
其中这三种方式的区别:
1. fork()出来的子进程是父进程的一个拷贝,即,子进程从父进程得到了数据段和堆栈段的拷贝,这些需要分配新的内存;而对于只读的代码段,通常使用共享内存的方式访问;而vfork()则是子进程与父进程共享内存空间, 子进程对虚拟地址空间任何数据的修改同样为父进程所见;clone()则由用户通过参clone_flags 的设置来决定哪些资源共享,哪些资源拷贝。
2. fork()不对父子进程的执行次序进行任何限制,fork()返回后,子进程和父进程都从调用fork函数的下一条语句开始行,但父子进程运行顺序是不定的,它取决于内核的调度算法;而在vfork()调用中,子进程先运行,父进程挂起,直到子进程调用了exec()或exit()之后,父子进程才有可能执行;clone()中由标志CLONE_VFORK来决定子进程在执行时父进程是阻塞还是运行,若没有设置该标志,则父子进程同时运行,设置了该标志,则父进程挂起,直到子进程结束为止。
简单介绍一下用fork()创建的父子进程的关系
#include <stdio.h>
int main(void)
{
int pid;
int count2=0;
int count1=0;
count1++;
count2++;
printf("count1=%d,count2=%d\n",count1,count2);
pid=fork(); //父进程执行了一遍,子进程执行了一遍
if(pid<0)
{
fprintf(stderr,"Fork Failed!");
exit(-1);
else if(pid=