您的位置:首页 > 运维架构 > Linux

进程管理(Linux内核设计与实现 整理)

2015-03-10 20:29 309 查看
一、进程线程相关概念

1.进程就是处于执行期的程序。但进程不仅仅局限于程序代码。还要包括其他资源,像打开的文件,挂起的信号,内核内部数据,处理器状态等
进程是处于执行期的程序以及相关资源的总称。

2.线程是进程中活动的对象。每个线程都拥有独立的程序计数器、进程栈和一组进程寄存器。

(查看进程和线程共享的部分???线程->fork->共享代码段,其他部分复制一份。类似的东西。要查询确认)

(全局变量在数据段,局部变量在栈,查类似的变量的存放位置????)

二、进程描述符和任务结构

1.内核把进程的列表存放在叫做任务列表的双向循环列表中。列表中的每一项都是类型为task_struct称为进程描述符。定义在 <linux/sched.h>文件中。该结构包含内核管理一个进程所需要的所有信息,能够完整的描述一个正在执行的程序。

2.linux通过slab来创建struct thread_info来创建和管理task_struct

3.进程通过pid来标识每一个进程(这个数字是有最大限制的)/proc/sys/kernel/pid_max

4.内核可以使用current指针来获取当前正在执行的进程

5.进程描述符中的state域描述进程当前的状态,可以通过set_task_state()或者set_current_state()来设置当前进程的状态

6.linux中进程存在一个明显的继承关系,所有进程都是PID为1的init进程的后代。在相应的task_struct中存在一个存放其父进程的task_struct的指针,也存在一个children的链表。分别是currect->parent指针和current->children链表
init进程的进程描述符是init_task。通过这一个关联就可以遍历整个系统中所有的进程。

三、进程创建

1.linux通过fork和exec两个步骤来进行进程的创建:
首先fork通过拷贝当前进程创建一个子进程,子进程与父进程区别仅仅在pid,ppid,某些资源和统计量
exec读取可执行文件并将其载入地址空间运行

2.写时拷贝机制
这是一种可以推迟甚至可以免除拷贝数据的技术。并不复制整个进程地址空间,而是父子进程共享,只有在需要写入的时候数据才会被复制,从而使各个进程拥有各自的拷贝。也就是说:资源的复制只有在有需要写入的时候才进行,在此之前只是以只读的方式共享。

3.fork
通过clone()系统调用实现fork,clone调用do_fork.do_fork在kernel/fork.c中
fork->clone->do_fork->copy_process
copy_process函数工作:
1.dup_task_struct为新进程创建一个内核栈,thread_info和task_struct,这些结构父子进程都是相同的。
2.检查确保创建子进程后,当前用户拥有进程数没有超过限制
3.父子进程区别开来,task_struct中的许多数据都要进行清0,其他大部分不变
4.子进程被设置为TASK_UNINTERRUPTIBLE保证不会投入运行
5.调用copy_flags更新task_struct中的flags成员
6.调用alloc_pid为新进程分配有效的PID
7.根据传给clone的标志,确定确定拷贝或共享资源
8.扫尾工作,并返回一个指向子进程的指针
回到do_fork,返回成功新创建的子进程就会唤醒并让其执行,虽然想但并非都能成功

4.vfork

四、线程

线程机制支持并发程序设计机制
在LINUX中线程被当作一个与其他进程共享某些资源的进程来进行管理,拥有自己的task_struct,所以在内核看起来他就像一个普通的进程

线程的创建和普通进程的创建类似,只不过调用clone时会传递一些参数来指明共享资源

创建线程
  clone(CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND,0)
fork
  clone(SIGCHLD,0)
vfork
  clone(CLONE_VFORK|CLONE_VM|SIGCHLD,0)

这些标志在<linux/sched.h>中定义

五、进程的终结
exit->do_exit(kernel/exit.c中)
释放资源和设置进程状态,该进程不会再被调度
但是不会删除其进程描述符task_struct.这样可以让系统在子进程结束后还可以获取他的信息

释放资源和删除进程描述符是分开进行的,父进程获得已终结的子进程的信息后,或通知内核不需要关注相关信息后就可以删除task_struct

使用release_task释放。至此进程所有内容全部释放掉

父进程先于子进程结束,需要为父进程重新找到一个父亲,否则会造成孤儿进程,僵死在那,拜拜消耗资源,
在do_exit中会调用exit_notify()该函数会调用forget_original_parenet之后调用find_new_reaper来寻找新父亲。
实在找不到可以让init作为其父亲
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: