Linux操作系统课程指导:Ch3进程管理_第1页
Linux操作系统课程指导:Ch3进程管理_第2页
Linux操作系统课程指导:Ch3进程管理_第3页
Linux操作系统课程指导:Ch3进程管理_第4页
Linux操作系统课程指导:Ch3进程管理_第5页
已阅读5页,还剩34页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

进程管理Outline

进程

进程描述符及任务结构

进程创建

线程在Linux中的实现

进程终止

小结2022/4/21LiangShi:LinuxOperatingSystems2上节课内容回顾

操作系统概念介绍

Linux操作系统版本介绍

Linux操作系统特有特征

SourceInsight源码阅读工具介绍

Linux进程描述符

Linux进程状态2022/4/21LiangShi:LinuxOperatingSystems8进程标识

使用进程描述符地址

进程和进程描述符之间有非常严格的一一对应关系,使得用32位进程描述符地址标识进程非常方便

使用PID(ProcessID,PID)

每个进程的PID都存放在进程描述符的pid域中2022/4/21LiangShi:LinuxOperatingSystems9进程的PID

进程的pid字段include/linux/types.hinclude/asm-XXX/posix_typesYYY.hPid最大值,参见kernel/pid.c顺序使用&&循环使用include/linux/threads.h2022/4/21LiangShi:LinuxOperatingSystems10用户如何获得一个进程的pid

系统调用getpid

关于进程组

使用组链表

所有进程共享组内第一个进程的pid

数据:tgid

单独一个进程可以看成只有一个进程的组

getpid返回组pid2022/4/21LiangShi:LinuxOperatingSystems11进程和进程的内核堆栈

Linux为每个进程分配一个8KB大小的内存区域,用于存放该进程两个不同的数据结构:

Thread_info

进程的内核堆栈进程处于内核态时使用,不同于用户态堆栈内核控制路径所用的堆栈很少,因此对栈和Thread_info来说,8KB足够了Thread_info2022/4/21LiangShi:LinuxOperatingSystems12Thread_union

C语言允许用如下的一个union结构来方便的表示这样的一个混合体include/linux/sched.hthread_info由体系结构相关部分定义阅读include/asm-x86/thread_info.h以及include/asm-x86/thread_info_32.h2022/4/21LiangShi:LinuxOperatingSystems13

进程描述符的分配/回收/访问

Thread_info的分配/回收/访问

alloc_thread_info

free_thread_info2022/4/21LiangShi:LinuxOperatingSystems142022/4/21LiangShi:LinuxOperatingSystems15current_thread_info

从刚才看到的thread_info和内核态堆栈之间的配对,内核可以很容易的从esp寄存器的值获得当前在CPU上运行的进程的描述符指针

因为这个内存区是8KB=213大小,内核必须做的就是让esp有13位的有效位,以获得进程描述符的基地址8191=8192-1=0x2000-1=0x1fff2022/4/21LiangShi:LinuxOperatingSystems取反:0xffffe000(最后13位为0)16Current宏2022/4/21LiangShi:LinuxOperatingSystems17Current宏的使用

Current宏可以看成当前进程的进程描述符指针,在内核中直接使用

举例:

比如current->pid返回在CPU上正在执行的进程的PID2022/4/21LiangShi:LinuxOperatingSystems18进程的创建

许多进程可以并发的运行同一程序,这些进程共享内存中程序正文的单一副本,但每个进程有自己的单独的数据和堆栈区

一个进程可以在任何时刻可以执行新的程序,并且在它的生命周期中可以运行几个程序

又如,只要用户输入一条命令,shell进程就创建一个新进程2022/4/21LiangShi:LinuxOperatingSystems20

传统的UNIX操作系统采用统一的方式来创建进程

子进程复制父进程所拥有的资源

缺点:

创建过程慢、效率低

事实上,子进程复制的很多资源是不会使用到的

现代UNIX内核通过引入三种不同的机制来解决这个问题2022/4/21LiangShi:LinuxOperatingSystems21

1、写时复制技术,Copy-On-Writing,COW写时复制技术允许父子进程能读相同的物理页。

只要两者有一个进程试图写一个物理页,内核就把这个页的内容拷贝到一个新的物理页,并把这个新的物理页分配给正在写的进程2022/4/21LiangShi:LinuxOperatingSystems22

2、轻量级进程允许父子进程共享许多数据结构

页表

打开的文件列表

信号处理

3、vfork

使用vfork创建的新进程能够共享父进程的内存地址空间。父进程在这个过程中被阻塞,直到子进程退出或者执行一个新的程序2022/4/21LiangShi:LinuxOperatingSystems23Linux的进程创建

Linux提供了几个系统调用来创建和终止进程,以及执行新程序

Fork,vfork和clone系统调用创建新进程

其中,clone创建轻量级进程,必须指定要共享的资源

exec系统调用执行一个新程序

exit系统调用终止进程(进程也可以因收到信号而终止)2022/4/21LiangShi:LinuxOperatingSystems24fork

fork系统调用创建一个新进程

调用fork的进程称为父进程

新进程是子进程

子进程几乎就是父进程的完全复制。它的地址空间是父进程的复制,一开始也是运行同一程序。

fork系统调用为父子进程返回不同的值2022/4/21LiangShi:LinuxOperatingSystems25exec

很多情况下,子进程从fork返回后很多会调用exec来开始执行新的程序

这种情况下,子进程根本不需要读或者修改父进程拥有的所有资源。

所以fork中地址空间的复制依赖于CopyOnWrite技术,降低fork的开销2022/4/21LiangShi:LinuxOperatingSystems26使用fork和exec的例子

If(result=fork()==0){

}elseif(result<0){

}

/*result==子进程的pid,父进程将会从这里继续执行*/

…/*子进程代码*/…if(execve(“new_program”,…)<0)perror(“execvefailed”);exit(1);perror(“forkfailed”)2022/4/21LiangShi:LinuxOperatingSystems27

分开这两个系统调用是有好处的

比如服务器可以fork许多进程执行同一个程序

有时程序只是简单的exec,执行一个新程序

在fork和exec之间,子进程可以有选择的执行一系列操作以确保程序以所希望的状态运行

重定向输入输出

关闭不需要的打开文件

改变UID或是进程组

重置信号处理程序

若单一的系统调用试图完成所有这些功能将是笨重而低效的

现有的fork-exec框架灵活性更强

清晰,模块化强2022/4/21LiangShi:LinuxOperatingSystems28do_fork

不论是fork,vfork还是clone,在内核中最终都调用了do_forkarch/x86/kernel/process_32.c2022/4/21LiangShi:LinuxOperatingSystems29kernel/fork

阅读do_fork;copy-process;…了解大致程序流程

???子进程从哪里开始执行,它的返回值是什么?

阅读copy_thread(arch/arm/kernel/process.c)

复制父进程的堆栈???

父进程的堆栈中有些什么???Fork系统调用???2022/4/21LiangShi:LinuxOperatingSystems30子进程的内核态堆栈高地址子进程的8Kunion用户态堆栈esp的值用户态下eip的值子进程的硬件上下文返回值eax被强制写0子进程恢复到用户态时需要的上下文espeipret_from_forkespThread_info低地址2022/4/21LiangShi:LinuxOperatingSystems31子进程的执行

fork后,子进程处于可运行状态,由调度器决定何时把CPU交给这个子进程

进程切换后因为eip指向ret_from_fork,所以CPU立刻跳转到ret_from_fork()去执行。

接着这个函数调用ret_from_sys_call(),此函数用存放在栈中的值装载所有寄存器,并强迫CPU返回用户态

回忆进程的切换2022/4/21LiangShi:LinuxOperatingSystems32arch/x86/kernel/entry_32.S2022/4/21LiangShi:LinuxOperatingSystems33内核线程

系统把一些重要的任务委托给周期性执行的进程

刷新磁盘高速缓存

交换出不用的页框

维护网络链接等待

内核线程与普通进程的差别

每个内核线程执行一个单独指定的内核函数

只运行在内核态

只使用大于PAGE_OFFSET的线性地址空间2022/4/21LiangShi:LinuxOperatingSystems34例如,0号进程创建1号进程init2022/4/21LiangShi:LinuxOperatingSystems35线程和进程的比较

Linux内核中没有线程的概念

没有针对所谓线程的调度策略

没有数据结构用来表示一个线程

一般线程的概念在linux中只是表现为一组共享资源的进程(每个这样的进程都有自己的进程描述符)

在其他系统中(比如windows)

线程是实实在在的一种运行抽象,提供了比进程更轻更快的调度单元

在linux中“线程”仅仅是表示多个进程共享资源的一种说法2022/4/21LiangShi:LinuxOperatingSystems36创建内核线程

Kerenl_thread()创建一个内核线程,并且只能由另一个内核线程来执行这个调用2022/4/21LiangShi:LinuxOperatingSystems372022/4/21LiangShi:LinuxOperatingSystems38进程树

进程0

进程1

…2022/4/21LiangShi:LinuxOperatingSystems39进程0

所有进程的祖先叫做进程0

在系统初始化阶段由start_kernel()函数从无到有手工创建的一个内核线程

Init_task

Init_thread_union

进程0最后的初始化工作创建init内核线程,此后运行cpu_idle,成为idle进程2022/4/21LiangShi:LinuxOperatingSystems40进程1

又称为init进程

由进程0在start_kernel调用rest_init创建

init进程PID为1,当调度程序选择到init进程时,init进程开始执行kernel_init()函数2022/4/21LiangShi:LinuxOperatingSystems41

kernel_init()为常规内核任务初始化一些必要的内核线程,如:

kflushd刷新‘脏’缓冲区中的内容到磁盘以归还内存

kswapd执行内存回收功能的线程

最后kernel_init()函数在init_post中调用execve()系统调用装入可执行程序init。从此,init内核线程变成一个普通的进程。但init进程从不终止,因为它创建和监控操作系统外层的所有进程的活动2022/4/21LiangShi:LinuxOperatingSystems422022/4/21LiangShi:LinuxOperatingSystems43撤销进程

进程终止

进程终止的一般方式是exit()系统调用。

这个系统调用可能由

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论