您好,欢迎访问三七文档
当前位置:首页 > IT计算机/网络 > linux/Unix相关 > Linux的进程管理(一)
Linux进程控制2主要内容1.进程、线程和轻量级进程的概念2.进程描述符3.进程状态4.如何标识一个进程5.进程内核栈6.进程间的关系7.与进程创建相关的系统调用3进程、线程和轻量级进程1.进程是程序执行的一个实例,是有限状态机的一次迁移过程。2.进程和程序的区别:动态与静止;多对一3.进程是资源分配的实体,这些资源包括:PID、task_struct、独立的内存地址空间、打开的文件描述符、信号处理函数对应表、挂起的信号等。4.线程是进程内一个独立的执行线路,是CPU调度的实体。5.线程共享所属进程的资源,但也有私有资源:栈、CPU寄存器状态、CPU时间片、优先级、线程局部存储TLS6.在Linux下,线程是利用轻量级进程机制实现的。7.多个轻量级进程共享同一套资源(同一内存空间),但具有不同的栈和CPU寄存器状态。4进程描述符task_struct1.进程描述符与进程一一对应,记录了与进程相关的所有信息2.进程描述符一般较大,(32位机1.7KB)3.创建进程描述符时使用了SLAB分配器5进程描述符task_structLinux2.6进程的状态include/linux/sched.h2020/1/23Linux操作系统分析7/65进程状态转换图EXIT_ZOMBIE或者EXIT_DEAD或者TASK_DEAD如何标识一个进程使用进程描述符地址进程和进程描述符之间有非常严格的一一对应关系,使得用32位进程描述符地址标识进程非常方便使用PID(ProcessID,PID)每个进程的PID都存放在进程描述符的pid域中进程的PID进程的pid字段Pid最大值,参见kernel/pid.c顺序使用&&循环使用include/linux/types.hinclude/asm-XXX/posix_typesYYY.hinclude/linux/threads.h10如何获得一个空闲的PID1.32位机上,PID最大为327672.为了循环使用PID编号,内核定义了一个pidmap_array位图,pidmap_array包含32768个位,刚好放到一个页框中。3.alloc_pid是如何实现的?(last_pid变量)11如何由PID获得对应的进程描述符1.如何实现find_task_by_pid(nr)?2.pidhashtable(固定数组,一般占4个页框,2048个表项)12structpidstructpid_link{intnr;//pid的数值structhlist_nodepid_chain;structlist_headpid_list;}structtask_struct{…structpid_linkpids[4];…}13如何由PID获得对应的进程描述符14/65进程和进程的内核堆栈Linux为每个进程分配一个8KB大小的内存区域,用于存放该进程两个不同的数据结构:Thread_info进程的内核态堆栈进程处于内核态时使用,不同于用户态堆栈内核控制路径所用的堆栈很少,因此对栈和Thread_info来说,8KB足够了Thread_info15用户态到内核态的切换1.用户态和内核态的区别?2.从用户态切换到内核态的3种方式:•系统调用:int80或sysinter•中断•异常3.从用户态切换到内核态后:•进程上下文(主要指页表)不切换•CPU自动切换到当前进程对应的内核态堆栈工作•CPU自动将用户态的寄存器状态和返回地址存放到内核栈Thread_unionC语言允许用如下的一个union结构来方便的表示这样的一个混合体thread_info由体系结构相关部分定义阅读include/asm-x86/thread_info.h以及include/asm-x86/thread_info_32.hinclude/linux/sched.hCurrent宏的使用Current宏可以看成当前进程的进程描述符指针,在内核中直接使用举例:比如current-pid返回在CPU上正在执行的进程的PIDcurrent宏的实现:#defineget_current()(current_thread_info()-task)#definecurrentget_current()current_thread_info的汇编代码是:movl$-THREAD_SIZE,%eax;andl%esp,%eax其中#defineTHREAD_SIZE(2*PAGE_SIZE)内核栈thread_infotask_struct*taskvoid*stacktask_struct21进程间的关系1.父子关系:parent,real_parent,children2.兄弟关系:sibling3.线程组关系:tgid,group_leader,thread_group4.进程组关系:signal-pgrp5.会话组关系:signal-session6.被调试关系:ptrace_children,ptrace_list7.系统中所有进程的task_struct被串成一个双向循环链表22进程间的关系进程启动23手工启动前台启动:shell中输入命令:program后台启动:shell中输入命令:program&调度启动利用at命令在指定时刻启动利用cron命令定期启动进程管理相关命令2425在程序中创建与终止进程•进程的创建和执行:–Linux中进程的创建进程被分解到两个单独的函数中取执行:fork()和exec函数族。首先,fork()通过拷贝当前进程创建一个子进程,子进程与父进程的区别仅仅在于不同的PID、PPID和某些资源及统计量。exec函数族负责读取可执行文件并将其载入地址空间开始运行。•进程的终止:–进程终结也需要做很多繁琐的收尾工作,系统必须保证进程所占用的资源回收,并通知父进程。Linux首先把终止的进程设置为僵尸状态,这个时候,进程无法投入运行了,它的存在只为父进程提供信息,申请死亡。父进程得到信息后,开始调用wait函数族,最终赐死子进程,子进程占用的所有资源被全部释放。fork函数•fork()–fork()函数用于从已存在的进程中创建一个新进程。新进程称为子进程,而原进程称为父进程。–使用fork()函数得到的子进程是父进程的一个复制品,它从父进程处继承了整个进程的地址空间,包括进程上下文、代码段、进程堆栈、内存信息、打开的文件描述符、信号控制设定、进程优先级、进程组号、当前工作目录、根目录、资源限制和控制终端等,而子进程所独有的只有它的进程号、资源使用和计时器等。•fork()函数语法:fork的另一个例子intmain(){intvar;pid_tpid;var=88;if((pid=fork())0){printf(forkerror\n);}elseif(pid==0){var++;}else{sleep(2);}printf(pid=%d,var=%d\n,getpid(),var);return0;}关于fork的两个问题连续调用3次fork,共可产生多少个进程?下面的程序一共输出多少个“-”?#includestdio.h#includesys/types.h#includeunistd.hintmain(void){inti;for(i=0;i2;i++){fork();printf(-);}return0;}子进程复制了父进程的哪些资源?•用户ID、用户组ID、进程组ID、会话ID•当前工作目录、根目录、环境变量•文件访问权限、资源访问权限•信号屏蔽位•打开的文件描述符•进程地址空间(数据段、代码段、堆栈段)•…Fork函数的应用逻辑—孙悟空逻辑intmain(){…….//遇到两个需要并行执行的任务:任务1和任务2pid=fork();//分身术if(pid==0){……//子进程处理任务1}else{……//父进程处理任务2}return0;}Fork函数应用例1intmain(){intfd1=open(“data_file1”,…);intfd2=open(“data_file2”,…);pid_tpid;if((pid=fork())==0){close(fd2);read(fd1,buffer,len);…//处理文件1的数据}else{close(fd1);read(fd2,buffer,len);…//处理文件2的数据}}Windows创建进程API—CreateProcessBOOLCreateProcess(LPCTSTRlpApplicationName,//新进程将要使用的可执行文件的名字(路径)LPTSTRlpCommandLine,//递给新进程的命令行字符串LPSECURITY_ATTRIBUTESlpProcessAttributes。LPSECURITY_ATTRIBUTESlpThreadAttributes,BOOLbInheritHandles,DWORDdwCreationFlags,LPVOIDlpEnvironment,LPCTSTRlpCurrentDirectory,LPSTARTUPINFOlpStartupInfo,LPPROCESS_INFORMATIONlpProcessInformation);CreateProcess的应用逻辑—黑社会逻辑Main.exe:主控程序,黑社会BossA.exe:专门处理任务A的程序,黑社会小弟B.exe:专门处理任务A的程序,黑社会小弟intmain(){…….//遇到两个需要并行执行的任务:任务A和任务BCreateProcess(“A.exe”,…);//叫个小弟来处理任务ACreateProcess(“B.exe”,…);//叫个小弟来处理任务B….//自己继续享受生活}exec函数•exec函数用于创建一个新的进程,新进程以另一个可执行程序为执行脚本。•exec创建的新进程“占用了”原进程的绝大部分资源,进程地址空间中装入了新的可执行程序。exec执行成功之后,原进程就“消失了”。•#includeunistd.h•intexecl(constchar*path,constchar*arg,...)•参数path:可执行文件的路径和名字构成的字符串•arg:新程序的命令行参数1•execl是一个不定参数函数,还可以传入多个命令行参数,最后一个参数必须是NULL。•返回值:-1表示出错exec函数的例子1#includeunistd.hintmain(intargc,char*argv[]){if(execl(/bin/echo,echo,executedbyexecl,NULL)0)perror(Erronexecl);}exec函数的例子2如果还想保留父进程怎么办??#includeunistd.hintmain(intargc,char*argv[]){if(fork()==0){if(execl(/bin/echo,echo,executedbyexecl,NULL)0)perror(Erronexecl);}//父进程做其他事情return0;}exec函数族exec函数族使用区别•exec函数族使用区别–查找方式•表中的前四个函数的查找方式都是完整的文件目录路径,而最后两个函数(以p结尾的函数)可以只给出文件名,系统就会自动从环境变量“$PATH”所指出的路径中进行查找。–参数传递方式•两种方式:逐个列举、将所有参数整体构造指针数组传递•以函数名的第五位字母来区分的,字母为“l”(list)的表示逐个列举的方式,其语法为char*arg;字母为“v”(vertor)的表示将所有参数整体构造指针数组传递,其语法为*constargv[]–环境变量•exec函数族可以默认系统的环境变量,也可以传入指定的环境变量。这里,以“e”(Enviromen)结尾的两个函数execle、execve就可以在envp[]中指定当
本文标题:Linux的进程管理(一)
链接地址:https://www.777doc.com/doc-3266815 .html