Linux的进程管理(一)_第1页
Linux的进程管理(一)_第2页
Linux的进程管理(一)_第3页
Linux的进程管理(一)_第4页
Linux的进程管理(一)_第5页
已阅读5页,还剩46页未读 继续免费阅读

下载本文档

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

文档简介

1、2 进程、线程和轻量级进程的概念 进程描述符 进程状态 如何标识一个进程 进程内核栈 进程间的关系 与进程创建相关的系统调用3 进程是程序执行的一个实例,是有限状态机的一次迁移过程。 进程和程序的区别:动态与静止;多对一 进程是资源分配的实体,这些资源包括:PID、task_struct、独立的内存地址空间、打开的文件描述符、信号处理函数对应表、挂起的信号等。 线程是进程内一个独立的执行线路,是CPU调度的实体。 线程共享所属进程的资源,但也有私有资源:栈、CPU寄存器状态、CPU时间片、优先级、线程局部存储TLS 在Linux下,线程是利用轻量级进程机制实现的。 多个轻量级进程共享同一套资源

2、(同一内存空间),但具有不同的栈和CPU寄存器状态。4 进程描述符与进程一一对应,记录了与进程相关的所有信息 进程描述符一般较大,(32位机1.7KB) 创建进程描述符时使用了SLAB分配器5Linux2.6进程的状态进程的状态include/linux/sched.h2021-10-28Linux操作系统分析操作系统分析7/65进程状态转换图进程状态转换图EXIT_ZOMBIE或者或者EXIT_DEAD或者或者TASK_DEAD如何如何标识一个进程标识一个进程使用进程描述符地址进程和进程描述符之间有非常严格的一一对应关系,使得用32位进程描述符地址标识进程非常方便使用PID (Process

3、 ID,PID)每个进程的PID都存放在进程描述符的pid域中进程的进程的PID进程的pid字段Pid最大值,参见最大值,参见kernel/pid.c顺序使用顺序使用&循环使用循环使用include/linux/types.hinclude/asm-XXX/posix_typesYYY.hinclude/linux/threads.h10 32位机上,PID最大为32767 为了循环使用PID编号,内核定义了一个pidmap_array位图, pidmap_array包含32768个位,刚好放到一个页框中。 alloc_pid是如何实现的?(last_pid变量)11 如何实现find

4、_task_by_pid(nr)? pidhash table(固定数组,一般占4个页框,2048个表项)12struct pid_link int nr; / pid的数值 struct hlist_node pid_chain; struct list_head pid_list;struct task_struct struct pid_link pids4; 1314/65进程和进程的进程和进程的内核内核堆栈堆栈Linux为每个进程分配一个8KB大小的内存区域,用于存放该进程两个不同的数据结构:Thread_info进程的内核态堆栈进程处于内核态时使用,不同于用户态堆栈内核控制路径内核

5、控制路径所用的堆栈很少,因此对栈和Thread_info来说,8KB足够了 Thread_info 15 用户态和内核态的区别? 从用户态切换到内核态的3种方式: 系统调用:int 80 或 sysinter 中断 异常 从用户态切换到内核态后: 进程上下文(主要指页表)不切换 CPU自动切换到当前进程对应的内核态堆栈工作 CPU自动将用户态的寄存器状态和返回地址存放到内核栈Thread_unionC语言允许用如下的一个union结构来方便的表示这样的一个混合体thread_info由体系结构相关部分定义由体系结构相关部分定义阅读阅读include/asm-x86/thread_info.h

6、以及以及include/asm-x86/thread_info_32.hinclude/linux/sched.hCurrent宏的使用宏的使用Current宏可以看成当前进程的进程描述符指针,在内核中直接使用举例:比如current-pid返回在CPU上正在执行的进程的PIDcurrent宏的实现:#define get_current() (current_thread_info()-task)#define current get_current()current_thread_info的汇编代码是:movl $-THREAD_SIZE, %eax; andl %esp, %eax其中#

7、define THREAD_SIZE (2*PAGE_SIZE)内核栈内核栈thread_infotask_struct*taskvoid* stacktask_struct21 父子关系:parent,real_parent,children 兄弟关系:sibling 线程组关系:tgid, group_leader, thread_group 进程组关系: signal-pgrp 会话组关系: signal-session 被调试关系:ptrace_children, ptrace_list 系统中所有进程的task_struct被串成一个双向循环链表22手工启动手工启动p前台启动:前台启

8、动:shellshell中输入命令:中输入命令:programprogramp后台启动:后台启动:shellshell中输入命令:中输入命令:program&program&调度启动调度启动p利用利用atat命令在指定时刻启动命令在指定时刻启动p利用利用croncron命令定期启动命令定期启动进程的创建和执行:进程的创建和执行: Linux中进程的创建进程被分解到两个单独的函数中取执行:fork()和exec函数族。首先,fork()通过拷贝当前进程创建一个子进程,子进程与父进程的区别仅仅在于不同的PID、PPID和某些资源及统计量。exec函数族负责读取可执行文件并将其载入地

9、址空间开始运行。进程的终止:进程的终止: 进程终结也需要做很多繁琐的收尾工作,系统必须保证进程所占用的资源回收,并通知父进程。Linux首先把终止的进程设置为僵尸状态,这个时候,进程无法投入运行了,它的存在只为父进程提供信息,申请死亡。父进程得到信息后,开始调用wait函数族,最终赐死子进程,子进程占用的所有资源被全部释放。 fork() fork()函数用于从已存在的进程中创建一个新进程。新进程称为子进程,而原进程称为父进程。 使用fork()函数得到的子进程是父进程的一个复制品,它从父进程处继承了整个进程的地址空间,包括进程上下文、代码段、进程堆栈、内存信息、打开的文件描述符、信号控制设定

10、、进程优先级、进程组号、当前工作目录、根目录、资源限制和控制终端等,而子进程所独有的只有它的进程号、资源使用和计时器等。 fork()函数语法:函数语法: forkfork的另一个例子的另一个例子int main()int var;pid_t pid;var = 88;if(pid = fork() 0) printf(fork errorn);else if (pid = 0) var+;else sleep(2);printf(pid = %d, var = %dn, getpid(), var);return 0;连续调用连续调用3 3次次forkfork,共可产生多少个进程?,共可产生

11、多少个进程?下面的程序一共输出多少个下面的程序一共输出多少个“-”-”?#include #include #include int main(void) int i; for(i=0; i2; i+) fork(); printf(-); return 0; 用户用户ID、用户组、用户组ID、进程组、进程组ID、会话、会话ID 当前工作目录、根目录、环境变量当前工作目录、根目录、环境变量 文件访问权限、资源访问权限文件访问权限、资源访问权限 信号屏蔽位信号屏蔽位 打开的文件描述符打开的文件描述符 进程地址空间(数据段、代码段、堆栈段)进程地址空间(数据段、代码段、堆栈段) int main(

12、). / 遇到两个需要并行执行的任务:遇到两个需要并行执行的任务:和和pid = fork(); / 分身术分身术if (pid = 0) / 子进程处理任务子进程处理任务1else / 父进程处理任务父进程处理任务2return 0;int main() int fd1 = open(“data_file1”, ); int fd2 = open(“data_file2”, ); pid_t pid; if(pid = fork() =0) close(fd2); read(fd1, buffer, len); / 处理文件处理文件1的数据的数据 else close(fd1); read(

13、fd2, buffer, len); / 处理文件处理文件2的数据的数据 BOOL CreateProcess( LPCTSTR lpApplicationName, /新进程将要使用的可执行文件的名字新进程将要使用的可执行文件的名字(路径路径) LPTSTR lpCommandLine, /递给新进程的命令行字符串递给新进程的命令行字符串 LPSECURITY_ATTRIBUTES lpProcessAttributes。 LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags

14、, LPVOID lpEnvironment, LPCTSTR lpCurrentDirectory, LPSTARTUPINFO lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation);Main.exe :主控程序,黑社会:主控程序,黑社会BossA.exe:专门处理任务:专门处理任务A的程序,黑社会小弟的程序,黑社会小弟B.exe:专门处理任务:专门处理任务A的程序,黑社会小弟的程序,黑社会小弟int main(). / 遇到两个需要并行执行的任务:遇到两个需要并行执行的任务:和和 CreateProcess(“A.exe”,

15、); / 叫个小弟来处理任务叫个小弟来处理任务A CreateProcess(“B.exe”, ); / 叫个小弟来处理任务叫个小弟来处理任务B . / 自己继续享受生活自己继续享受生活exec函数用于创建一个新的进程,新进程以另一个可执行程函数用于创建一个新的进程,新进程以另一个可执行程序为执行脚本。序为执行脚本。exec创建的新进程创建的新进程“占用了占用了”原进程的绝大部分资源,进程原进程的绝大部分资源,进程地址空间中装入了新的可执行程序。地址空间中装入了新的可执行程序。exec执行成功之后,原执行成功之后,原进程就进程就“消失了消失了”。#include int execl(const

16、 char *path, const char *arg, .) 参数参数path : 可执行文件的路径和名字构成的字符串可执行文件的路径和名字构成的字符串arg: 新程序的命令行参数新程序的命令行参数1execl是一个不定参数函数,还可以传入多个命令行参数,最是一个不定参数函数,还可以传入多个命令行参数,最后一个参数必须是后一个参数必须是NULL。返回值:返回值:-1 表示出错表示出错#include int main(int argc, char *argv) if(execl(/bin/echo, echo, executed by execl, NULL)0)perror(Err on

17、 execl);如果还想保留父进程怎么办?如果还想保留父进程怎么办? #include int main(int argc, char *argv) if(fork()=0) if(execl(/bin/echo, echo, executed by execl, NULL)0)perror(Err on execl); / 父进程做其他事情父进程做其他事情 return 0; exec函数族使用区别函数族使用区别 查找方式查找方式 表中的前四个函数的查找方式都是完整的文件目录路径,而最后两个函数(以p结尾的函数)可以只给出文件名,系统就会自动从环境变量“$PATH”所指出的路径中进行查找。

18、参数传递方式参数传递方式 两种方式:逐个列举、将所有参数整体构造指针数组传递 以函数名的第五位字母来区分的,字母为“l”(list)的表示逐个列举的方式,其语法为char *arg;字母为“v”(vertor)的表示将所有参数整体构造指针数组传递,其语法为*const argv 环境变量环境变量 exec函数族可以默认系统的环境变量,也可以传入指定的环境变量。这里,以“e”(Enviromen)结尾的两个函数execle、execve就可以在envp中指定当前进程所使用的环境变量 在在Unix时代时代exec经常与经常与fork配合使用,但这样做了大配合使用,但这样做了大量的无用功,效率低下(

19、为什么?)。量的无用功,效率低下(为什么?)。 为了解决该问题,在为了解决该问题,在Unix时代创建了时代创建了vfork函数与函数与exec配合。配合。vfork函数不复制父进程的资源,而是共享父函数不复制父进程的资源,而是共享父进程资源,直到碰到进程资源,直到碰到exec函数才开始复制父进程的函数才开始复制父进程的部分资源(不包括进程地址空间)。部分资源(不包括进程地址空间)。 在在Linux时代,时代,fork函数实现中引入了函数实现中引入了“写时拷贝写时拷贝Copy On Write”技术,技术,fork+exec的配合效率也很高。的配合效率也很高。 Linux时代,时代,vfork几

20、乎没有存在的必要,只被用在极几乎没有存在的必要,只被用在极少数场合。少数场合。 vfork()其功能类似于fork(),但是有以下两点显著的不同: vfork()不同于fork() ,它没有复制自己的进程地址空间,而是共享父进程的,所以,子进程的改变也会引起父进程的改变 vfork()创建后子进程总是立即优先于父进程执行的 ,在子进程exec或者exit后,才会执行父进程。 vfork()函数语法:函数语法: pid_t vfork (void);int clone(int (*fn)(void *), void *child_stack, int flags, void *arg); clo

21、ne可以让你有选择性的继承父进程的资源,你可以选择想vfork一样和父进程共享一个虚存空间,从而使创造的是线程,你也可以不和父进程共享,你甚至可以选择创造出来的进程和父进程不再是父子关系,而是兄弟关系。clone还可以为新进程指定EIP的值(令EIP指向fn指向的函数)fork的子进程和父进程不共享任何资源。Vfork = clone(EIP, ESP, CLONE_VFORK|CLONE_VM, 0);CLONE_PARENT 创建的子进程的父进程是调用者的父进程,新进程与创建它创建的子进程的父进程是调用者的父进程,新进程与创建它的进程成了的进程成了“兄弟兄弟”而不是而不是“父子父子” CL

22、ONE_FS 子进程与父进程共享相同的文件系统,包括子进程与父进程共享相同的文件系统,包括root、当前目录、当前目录、umask CLONE_FILES 子进程与父进程共享相同的文件描述符(子进程与父进程共享相同的文件描述符(file descriptor)表)表 CLONE_NEWNS 在新的在新的namespace启动子进程,启动子进程,namespace描述了进程的文件描述了进程的文件hierarchy CLONE_SIGHAND 子进程与父进程共享相同的信号处理(子进程与父进程共享相同的信号处理(signal handler)表)表 CLONE_PTRACE 若父进程被若父进程被tr

23、ace,子进程也被,子进程也被trace CLONE_VFORK 父进程被挂起,直至子进程释放虚拟内存资源父进程被挂起,直至子进程释放虚拟内存资源 CLONE_VM 子进程与父进程运行于相同的内存空间子进程与父进程运行于相同的内存空间 CLONE_PID 子进程在创建时子进程在创建时PID与父进程一致与父进程一致 CLONE_THREAD Linux 2.4中增加以支持中增加以支持POSIX线程标准,子进程与父进程共线程标准,子进程与父进程共享相同的线程群享相同的线程群 exit()和和_exit() exit()和_exit()函数都是用来终止进程的。当程序执行到exit()或_exit()时,进程会无条件地停止剩下的所有操作,清除包括各种数据结构,并终止本进程的

温馨提示

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

评论

0/150

提交评论