• 822.00 KB
  • 2022-04-29 14:44:52 发布

最新Linux原理及应用02课件PPT.ppt

  • 77页
  • 当前文档由用户上传发布,收益归属用户
  1. 1、本文档共5页,可阅读全部内容。
  2. 2、本文档内容版权归属内容提供方,所产生的收益全部归内容提供方所有。如果您对本文有版权争议,可选择认领,认领后既往收益都归您。
  3. 3、本文档由用户上传,本站不保证质量和数量令人满意,可能有诸多瑕疵,付费之前,请仔细先通过免费阅读内容等途径辨别内容交易风险。如存在严重挂羊头卖狗肉之情形,可联系本站下载客服投诉处理。
  4. 文档侵权举报电话:19940600175。
'Linux原理及应用02 第2章Linux进程管理程序是为了完成某种任务而设计的软件,是存储在磁盘上包含可执行的机器指令和数据的静态实体。进程是一个程序的一次执行的过程,在操作系统中执行特定的任务,是一个随执行过程不断变化的实体。进程是Linux系统中基本的调度单位。进程具有独立的权限与职责,如果系统中某个进程崩溃,它不会影响到其余的进程。每个进程运行在其各自的虚拟地址空间中,通过内核控制下的通信机制,它们之间才能发生联系。进程在生命期内将使用系统中的资源。它利用系统中的CPU来执行指令,用物理内存来放置指令和数据。使用文件系统提供的功能打开并使用文件,同时直接或者间接地使用物理设备。 2.1Linux进程在Linux系统中,进程被称为任务。进程存在于系统的内存之中,是操作系统可感知、可控制的动态实体。Linux的进程在处理机上运行时,处理机提供了两种不同的执行状态:内核态(kernelmode)用户态(usermode) 2.1Linux进程进程上下文:系统提供给进程的处于动态变化的运行环境总和系统中的每一个进程都有它自己的上下文Linux操作系统包括三种不同类型的进程,每种进程都有自己的特点和属性:(1)交互进程——由一个Shell启动的进程。交互进程既可以在前台运行,也可以在后台运行(2)批处理进程——这种进程和终端没有联系,是一个进程序列(3)守护进程——Linux系统启动时启动的进程,并在后台运行 2.2描述进程的数据结构Linux的进程控制块用任务结构体task_struct描述。Linux在内核空间专门开辟一个指针数组task,该数组的每一个元素是一个指向任务结构体的指针,所以task数组又称为task向量。将所有进程控制块task_struct的指针存储在task数组中,以便有效地管理。task数组大小限制了系统并发执行的进程总数,而物理内存的大小决定了系统中的最大进程数。在2.4.0版本中,每个task_struct结构占1680字节。 2.2描述进程的数据结构task_struct容纳了一个进程的所有信息,我们主要对如下几个方面的信息进行介绍。(1)进程的状态和标志信息(2)进程的调度信息(3)进程的标识信息(4)进程间通信信息(5)进程的家族关系(6)时间和定时信息(7)文件系统信息(8)存储管理信息(9)CPU现场保留信息 2.2.1进程的状态和标志信息1.state项task_struct中的state项表示进程当前的状态。Linux系统的2.2.X版本进程共有六种状态,包括运行状态、可中断等待状态、不可中断等待状态、僵死状态、暂停状态和交换状态,而在2.4.0版本中取消了交换状态,加入独占状态。可运行状态(TASK_RUNNING):可运行状态进程组成队列RUN_QUEUE。等待状态:Linux进程有两种等待状态:可中断的等待状态(TASK_INTERRUPTIBLE)。可中断等待进程可以被信号中断;当进程处于可中断等待状态时,系统不会调度该进程执行。当系统产生一个中断或者释放了进程正在等待的资源,或者进程收到一个信号,都可以唤醒进程转换到可运行状态。不可中断等待状态(TASK_UNINTERRUPTIBLE)。不可中断等待进程直接在硬件条件等待,并且任何情况下都不可中断。处于不可中断状态的进程只有被使用wake_up()函数明确唤醒时才能转换到可运行的就绪状态。 2.2.1进程的状态和标志信息暂停状态(TASK_STOPPED):通常是通过接收一个信号,如SIGSTOP、SIGTSTP、SIGTTIN或SIGTTOU而暂停运行。正在被调试的进程可能处于暂停状态。可向其发送SIGCONT信号让进程转换到可运行状态。僵死状态(TASK_ZOMBIE):当进程已停止运行,但其父进程还没有询问其状态时,则称该进程处于僵死状态,是表示进程结束但尚未消亡的一种状态。交换状态(SWAPPING):处于交换状态的进程正在执行内存、外存的交换工作。这个状态在2.2.X版的内核中基本已经不使用,在2.4.X版中没有这种状态。独占状态(EXCLUSIVE):严格地说,这不是一种独立的进程状态。它应该是等待状态的一种,处于独占状态的进程位于等待队列中,当等待的事件发生时,只有处于这种状态的进程被唤醒,其他处于可中断和不可中断等待状态的进程则继续等待。引入独占状态后,如果事件发生,只唤醒处于独占状态的那个进程,这就可以大大提高Apache这类Web应用的效率,使Linux更适合网络服务器的角色。 2.2.1进程的状态和标志信息Linux系统(2.2.x-2.4.x版本)进程状态表进程状态值说明TASK_RUNNING0运行态TASK_INTERRUPTIBLE1等待态,可中断TASK_UNINTERRUPTIBLE2等待态,不可中断TASK_ZOMBIE4僵死态TASK_STOPPED8暂停态TASK_SWAPPING16交换态(2.4.x版本无)TASK_EXCLUSIVE32独占态 2.2.1进程的状态和标志信息Linux系统(2.6版本)进程状态表进程状态值说明TASK_RUNNING0运行态TASK_INTERRUPTIBLE1等待态,可中断TASK_UNINTERRUPTIBLE2等待态,不可中断TASK_ZOMBIE4僵死态TASK_STOPPED8暂停态TASK_DEAD16已经退出且不需要父进程来回收的进程 图1Linux系统进程状态及转换示意图图1同时也记录了一个进程在整个生命周期的变化过程。从图的左下方开始看,系统在某种特定的情况下,响应某个要求,首先分配各种资源,创建一个新的进程,进程进入就绪队列 所有的进程必须在就绪之后,才有资格竞争CPU,进入运行状态。这样,进程的整个生命周期中,大致的转换路径总是沿着三个闭合回路进行。就绪状态和执行状态形成第一个回路。进程进入就绪态,放入可执行队列等待,一旦被调度函数选中,就切换现场,进入运行状态,等自己的时间片耗尽之后,马上保护现场,让出CPU,转入就绪状态,等待新的调度。执行状态、等待状态和就绪状态形成第二个回路。处于执行状态的进程,有时需要等待某个事件或某种资源的发生,这时,继续占有CPU也无法开展工作,就转入等待状态,CPU由下一个被调度的进程占有。当等待进程所等待的事件发生后,等待进程被唤醒,进入就绪状态。 执行状态、暂停状态和就绪状态构成第三个回路。当接收到某种特殊的信号,比如SIGSTOP(Linux的停止信号)时,处于执行状态的进程放弃CPU,保护现场之后,进入暂停状态,直到获得另外一个特殊的信号才进入就绪状态。一个处于执行状态的进程调用退出函数exit之后,进程就会进入僵死状态,这种状态下,进程释放了PCB之外的所有系统资源。也就是说,它在系统中只留下这个进程的一个PCB。僵死进程的父进程通过PCB了解到该进程所处的状态后,采取相应的处理措施,回收PCB,这个进程就完成了它的使命,从僵死走向彻底消亡,上图右上方的虚箭头表示了这种结局。 2.2.1进程的状态和标志信息2.flags项task_struct中的flags项表示进程的标志。进程标志值含义PF_ALIGNWARN正在打印"对齐"警告信息PF_STARTING正在创建进程PF_EXITING进程正在退出PF_FORKNOEXEC进程刚创建,但还没执行PF_SUPERPRIV使用超级用户特权PF_DUMPCOREdumpedcorePF_SIGNALED进程被信号(Signal)终止PF_MEMALLOC正在分配内存PF_VFORK对于用vfork创建的进程,退出前正在唤醒父进程PF_USEDFPU该进程使用FPU(SMPonly) 2.2.2进程的调度信息进程的类别、调度策略、优先级等调度属性反映了进程的调度信息。task_struct中的policy、priority、rt_priority、counter、nice等项与进程调度有关。policy表示进程的进程调度策略,可以通过系统调用sys_sched_setscheduler()更改(kernel/sched.c)。Linux操作系统采用的调度策略见下表。调度策略值说明SCHED_OTHER0非实时进程,基于优先权的轮转法SCHED_FIFO1实时进程,先进先出算法SCHED_RR2实时进程,基于优先权的轮转法 2.2.2进程的调度信息priority表示进程优先级,其值给出了进程每次获取CPU后,可使用的时间(按jiffies计)。rt_priority给出实时进程的优先级,rt_priority+1000给出进程每次获取CPU后,可使用的时间(同样按jiffies计)。在轮转法(roundrobin)调度时表示进程当前还可运行多久。在进程开始运行时被赋为priority的值,以后每隔一个tick(时钟中断)递减1,减到0时引起新一轮调度。重新调度将从run-queue队列选出counter值最大的就绪进程获得CPU,因此counter起到了进程的动态优先级的作用(priority则是静态优先级)。counter表示进程当前还拥有的时间片,nice表示普通进程的动态优先级,可对优先权进行动态调整。 2.2.3进程的标识信息task_struct中:pid、ppid等项描述了进程的标识信息。pid是进程标识号,ppid是其父进程标识号。uid和gid:表示运行进程的用户标识号和组标识号。euid和egid:表示运行进程的有效用户标识号和有效组标识号。fsuid和fsgid:表示运行进程的文件系统用户标识号和文件系统组标识号。suid和sgid:表示运行进程的备份用户标识号和备份组标识号。 2.2.4进程的通信信息Linux支持经典的UnixIPC机制,如信号、管道以及系统V中IPC机制,包括共享内存、信号灯和消息队列。task_struct结构中存储了与进程通信有关的信息。与进程通信有关的项有sigpending,signal,blocked,*sig,exit_signal,semundo,*semsleeping等。sigpending本身也是一个结构体,包含关于本进程中未决信号的信息。signal域记录进程接收到的信号类型,在I386体系结构中共32位。blocked表示阻塞信号的掩码,*sig是指向信号处理函数表的指针。exit_signal表示进程终止的信号。semundo表示进程要释放的信号量,*semsleeping指向与信号量操作相关的等待队列。 2.2.5进程的家族关系Linux系统中所有进程都是相互联系的。*p_opptr项是指向祖先进程任务结构体的指针;*p_pptr项是指向父进程任务结构体的指针;*p_cptr项是指向子进程任务结构体的指针;*p_ysptr项是指向弟进程任务结构体的指针;*p_osptr项是指向兄进程任务结构体的指针。 2.2.5进程的家族关系Linux的所有进程还组成一个双向链表。*next_task项指向下一进程任务结构体的指针;*prev_task项是指向上一进程任务结构体的指针。链表的头和尾都是init_task(即0号进程)。Linux还把所有处于可运行状态的进程通过两个指针*next_run和*prev_run连接形成双向循环队列RUN_QUEUE。 2.2.6时间和定时信息进程是动态的,在task_struct结构中还有表示时间的数据项。start_time项表示进程创建的时间;utime项表示进程在用户态下耗费的时间;stime项表示进程在内核态下耗费的时间;cutime项表示所有子进程在用户态下耗费的时间;cstime项表示所有子进程在内核态下耗费的时间;timeout项表示进程申请延时。 2.2.7文件系统信息task_struct结构保存了进程与文件系统相关的信息。进程可以自由地打开或关闭文件。*fs指针指向进程的可执行映象所在的文件系统;*files指针指向进程打开的文件。下图表明系统中的每个进程有2个数据结构描述文件系统相关的信息。 2.2.7文件系统信息 2.2.8存储管理信息进程是和内存联系在一起的,task_struct结构中有如下几个与内存相关的数据项:*mm进程的虚存信息;*ldt进程的局部描述符表指针;saved_kernel_stack内核态下堆栈的指针;kernel_stack_page内核态下堆栈的页表指针; 2.2.8存储管理信息下图显示了一个简单进程的虚存的布局以及管理它的内核数据结构。 2.2.9CPU现场保留信息进程运行时,它将使用处理器的寄存器以及堆栈等等。进程被挂起时,进程的上下文——所有的CPU相关的状态必须保存在它的task_struct结构中。当调度器重新调度该进程时,所有上下文被重新设定。CPU现场保留信息包括CPU寄存器、堆栈等环境。 2.2.10task_struct的作用task_struct是进程存在的唯一标志,用来描述系统中的进程或任务。在Linux系统中,用NR_TASKS定义task数组的大小,NR_TASKS的缺省值一般为512。创建新进程时,Linux将从系统内存中分配一个task_struct结构并将其加入task数组。当前运行进程的结构用current指针来指示。 图3-2父进程和子进程的内存映像 2.3Linux的进程控制进程控制就是研究如何建立、撤消、阻塞或唤醒一个进程,从而使进程状态发生变化。在传统的Unix环境下,有两个基本的操作用于创建和修改进程:函数fork()用来创建一个新的进程,该进程几乎是当前进程的一个完全拷贝;函数族exec()用来启动另外的进程以取代当前运行的进程。Linux的进程控制和传统的Unix进程控制基本一致,只在一些细节的地方有些区别。 2.3.1创建进程系统启动时总是处于内核模式,此时只有一个进程:初始化进程。在系统初始化的最后,初始化进程启动一个称为init内核线程(或进程),然后保留在idle状态。如果没有任何事要做,调度管理器将运行idle进程。idle进程是唯一不是动态分配task_struct的进程,它的task_struct在内核构造时静态定义,叫init_task,其标识号为0。init内核线程是系统中第一个真正有用的进程,其标识号为1。它负责完成系统的一些初始化设置任务,以及执行系统初始化程序。init程序使用/etc/inittab作为脚本文件来创建系统中的新进程。这些新进程又创建各自的新进程。 2.3.1创建进程Linux系统中,进程是进程映像的执行过程,也就是正在执行的进程实体。它由三部分组成:(1)用户级上、下文。主要成分是用户程序;(2)寄存器上、下文。由CPU中的一些寄存器的内容组成,如PC,PSW,SP及通用寄存器等;(3)系统级上、下文。包括OS为管理进程所用的信息,有静态和动态之分。 2.3.1创建进程可用fork()系统调用来创建一个新进程。系统调用格式:pid=fork()fork()返回值意义如下:0:在子进程中,表示当前进程是子进程。>0:在父进程中,返回值为子进程的id值(唯一标识号)。-1:创建失败。如果fork()调用成功,它向父进程返回子进程的pid,并向子进程返回0,即fork()被调用了一次,但返回了两次。此时OS在内存中建立一个新进程,所建的新进程是调用fork()父进程的副本,称为子进程。子进程继承了父进程的许多特性,并具有与父进程完全相同的用户级上下文。父进程与子进程并发执行。 2.3.1创建进程内核为fork()完成以下操作:(1)为新进程分配一进程表项和进程标识号(2)检查同时运行的进程数目(3)拷贝进程表项中的数据(4)子进程继承父进程的所有文件,对父进程当前目录和所有已打开的文件表项中的引用计数加1。(5)为子进程创建进程上、下文(6)子进程执行虽然父进程与子进程程序完全相同,但每个进程都有自己的程序计数器PC(注意子进程的PC开始位置),然后根据pid变量保存的fork()返回值的不同,执行了不同的分支语句。 2.3.1创建进程一个具体使用fork创建进程的实例。(2-a)#includeintforkvar=0;intmain(){ intpid;pid=fork();//系统调用,创建进程if(pid<0){//创建不成功,出错printf(“Forkfailed.”);exit(1);//系统调用}elseif(pid==0){//子进程执行printf(“I"mthechildprocess!n”);Forkvar=2;printf(“parent,forkvar=%d”,forkvar); }else{//父进程执行wait();//系统调用,等待子进程完成printf(“I"mtheparentprocess!n”);forkvar++;printf(“parent,forkvar=%d”,forkvar);}exit(0);} 2.3.1创建进程#includemain(){inti;if(fork()==0){/*子进程程序*/for(i=1;i<10;i++)printf(“BBBn”);}else{/*父进程程序*/for(i=1;i<10;i++)printf(“AAAn");}}(2-b)利用vi编辑器输入上述代码后,存盘退出,再用gcc编译执行。格式如下:gcc源文件名-o执行文件名最后,在shell提示符下输入./执行文件名就可执行该文件。 2.3.2执行进程子进程为了和父进程完成不同的任务,利用exec()系统调用装载新的进程映像,放弃从父进程那里拷贝过来的内容。exec是一个函数族,有6个函数,分别是:intexecl(constchar*path,constchar*arg,...);intexeclp(constchar*file,constchar*arg,...);intexecle(constchar*path,constchar*arg,...,char*constenvp[]);intexecv(constchar*path,char*constargv[]);intexecvp(constchar*file,char*constargv[]);intexecve(constchar*path,char*constargv[],char*constenvp[]);其中只有execve是真正意义上的系统调用,其它都是在此基础上经过包装的库函数。系统调用execve()对当前进程进行替换,替换者为一个指定的程序,其参数包括文件名(filename)、参数列表(argv)以及环境变量(envp)。 2.3.2执行进程结合fork与exec的使用可以启动另一程序执行但自己仍继续运行。下面代码显示如何启动运行其它程序:charcommand[256];//2-cvoidmain(){intrtn;/*子进程的返回数值*/while(1){/*从终端读取要执行的命令*/printf(">");fgets(command,256,stdin);command[strlen(command)-1]=0;if(fork()==0){/*子进程执行此命令*/execlp(command,command);/*如果exec函数返回,表明没有正常执行命令,打印错误信息*/perror(command);exit(errorno);}else{/*父进程,等待子进程结束,并打印子进程的返回值*/wait(&rtn);printf("childprocessreturn%dn",.rtn);}}}/*此程序从终端读入命令并执行之,完成后,父进程继续等待从终端读入命令。*/ 2.3.3等待进程父进程可用系统调用wait()等待它的一个子进程的结束,wait()的参数指定了父进程等待的子进程。wait的函数原型是:#include/*提供类型pid_t的定义*/#includepid_twait(int*status)进程一旦调用了wait,就立即阻塞自己,由wait自动分析是否当前进程的某个子进程已经退出,如果让它找到了这样的子进程,wait就会收集这个子进程的信息,并把它彻底销毁后返回;如果没有找到这样一个子进程,wait就会一直阻塞,直到有一个出现为止。如果参数status的值不是NULL,wait就会把子进程退出时的状态取出并存入其中,这是一个整数值。 2.3.3等待进程waitpid系统调用在Linux函数库中的原型是:#include/*提供类型pid_t的定义*/#includepid_twaitpid(pid_tpid,int*status,intoptions)从本质上讲,系统调用waitpid和wait的作用是完全相同的,但waitpid多出了两个可由用户控制的参数pid和options,从而为编程提供了另一种更灵活的方式。waitpid等待指定的子进程直到子进程返回。pid>0,等待指定的进程(pid);pid=0,等待任何一个组ID和调用者的组ID相同的进程;pid=-1时等同于wait调用;pid<-1时等待任何一个组ID等于pid绝对值的进程。status和wait的意义一样。options可以决定父进程的状态,可以取两个值。WNOHANG:当没有子进程存在时父进程立即返回。WUNTRACED:当子进程结束时waitpid返回,但是子进程的退出状态不可得到。 2.3.3等待进程下面是一个利用waitpid函数的实例。(2-d)#include#include#include#include#includeintmain(void){pid_tchildpid;intstatus;childpid=fork();if(-1==childpid){perror("fork()");exit(EXIT_FAILURE);}elseif(0==childpid){puts("Inchildprocess");sleep(3);//让子进程睡眠3秒printf("tchildpid=%dn",getpid());printf("tchildppid=%dn",getppid());exit(EXIT_SUCCESS);}else{waitpid(childpid,&status,0);puts("Inparentprocess");printf("tparentpid=%dn",getpid());printf("tparentppid=%dn",getppid());printf("tchildprocessexitedwithstatus%dn",status);}exit(EXIT_SUCCESS);} 2.3.3等待进程编译后运行,结果如下:Inchildprocesschildpid=4469childppid=4468Inparentprocessparentpid=4468parentppid=4379childprocessexitedwithstatus0如果将上面“waitpid(childpid,&status,0);”行注释掉,程序执行效果如下:InchildprocessInparentprocessparentpid=4481parentppid=4379childprocessexitedwithstatus1331234400childpid=4482childppid=1从运行结果中可以看出,子进程还没有退出,父进程已经退出了。 2.3.4终止进程当需要一个进程结束或进程希望终止自己时,可通过系统调用exit()来实现。在2.4.4版内核中,exit是第1号调用,其在Linux函数库中的原型是:#includevoidexit(intstatus);无论在程序中的什么位置,只要执行到exit系统调用,进程就会停止剩下的所有操作,清除包括PCB在内的各种数据结构,并终止本进程的运行。 2.3.4终止进程请看下面的程序(2-e)#includemain(){printf("Thisistheexampleofexit!n");exit(0);printf("neverbeRUN!n");}编译后运行:$gccexit_example.c-oexit_example$./exit_exampleThisistheexampleofexit!可以看到,程序并没有打印后面的"neverbeRUN",因为在此之前,在执行到exit(0)时,进程就已经终止了。 2.4Linux进程调度在Linux中,进程不能被抢占。只要能够运行它们就不能被停止。当进程必须等待某个系统事件时,它才决定释放出CPU。进程常因为执行系统调用而需要等待。由于处于等待状态的进程还可能占用CPU时间,所以Linux采用了预加载调度策略。在此策略中,每个进程只允许运行很短的时间:200毫秒,当这个时间用完之后,系统将选择另一个进程来运行,原来的进程必须等待一段时间以继续运行。这段时间称为时间片。 2.4Linux进程调度Linux系统进行调度时,把进程分成两类:普通进程。对普通进程,一律采用基于动态优先级的轮转法(SCHED-OTHER)。实时进程。实时进程的优先级要高于其它进程。实时进程又有两种策略:时间片轮转(SCHED-RR)。先进先出(SCHED-FIFO)。进程类型由policy域表示。 2.4Linux进程调度进程的权值作为选择进程的唯一依据,权值大的优先调度。进程的权值由priority域和rt_priority域确定。普通进程的优先级随剩余时间片counter值在动态变化。实时进程的权值取决于实时优先级rt_priority。priority域是调度管理器分配给进程的优先级。同时也是进程允许运行的时间(jiffies)。系统调用renice可以改变进程的优先级。rt_priority域是实时进程的优先级,且它们的优先级要高于非实时进程。调度器使用这个域给每个实时进程一个相对优先级。同样可以通过系统调用来改变实时进程的优先级。counter域是进程允许运行的时间(保存在jiffies中)。进程首次运行时为进程优先级的数值,它随时间变化递减。 2.4Linux进程调度每次调度管理器运行时将进行下列操作:(1)处理当前进程(2)选择运行进程(3)切换进程上下文 2.4Linux进程调度schedule()函数在系统中被频繁调用,该函数被调用的时机有:(1)进程状态转换的时刻;(2)可运行进程队列中新增加一个进程时;(3)当前进程的时间片用完时;(4)进程从系统调用返回到用户态时;(5)内核处理完中断后,进程返回到用户态时; 2.5进程的虚拟内存进程的虚拟内存包括可执行代码和多个资源数据。首先加载的是程序映象,是由可执行代码和数据组成的。此映象文件包含所有加载可执行代码所需的信息,同时还将程序数据连接进入进程的虚拟内存空间。然后在执行过程中,进程定位可以使用的虚拟内存,以包含正在读取的文件内容。新分配的虚拟内存必须连接到进程已存在的虚拟内存中才能够使用。 2.5进程的虚拟内存Linux内核需要管理所有的虚拟内存地址,每个进程虚拟内存中的内容在其task_struct结构中有vm_area_struct结构mm_struct结构 2.5进程的虚拟内存为了加快存取,Linux另外把vm_area_struct数据结构排列成一个AVL(Adelson-Velskii和Landis)树(也称平衡树)。这棵树上,每个vm_area_struct(或节点)有一左一右两个指针指到它的邻近的vm_area_struct结构。左指针指向的节点虚拟地址小于右指针指向的节点。寻找正确的节点时,Linux从树根开始,根据每个节点的左右指针指向的地址的大小关系决定向何处去找,直到找到为止。 2.5进程的虚拟内存当进程请求分配虚拟内存时,Linux实际上并不直接分配物理内存。它只是创建一个vm_area_struct结构来描述此虚拟内存,此结构被连接到进程的虚拟内存链表中。当进程试图对新分配的虚拟内存进行写操作时,系统将发生pagefault(页失效)。处理器会尝试解析此虚拟地址,但是如果找不到对应此虚拟地址的页表入口时,处理器将放弃解析并产生页面错误异常,由Linux内核来处理。Linux则查看此虚拟地址是否在当前进程的虚拟地址空间中。如果是Linux会创建正确的PTE并为此进程分配物理页面。然后进程将从页面错误处开始继续执行,由于物理内存已经存在,所以不会再产生页面异常,可以继续运行。 2.6进程访问的文件任务结构体task_struct给出了两个描叙系统中每个进程所使用的文件系统相关信息。第一个fs_struct包含了指向进程的VFSinode和其屏蔽码。第二个数据结构files_struct包含了进程当前所使用的所有文件的信息。程序从标准输入中读取并写入到标准输出中去。任何错误信息将输出到标准错误输出。这些文件有些可能是真正的文件,有的则是输出/输入终端或者物理设备,但程序都将它们视为文件。 2.6进程访问的文件每个文件有一个描述符,files_struct最多可以包含256个文件数据结构,它们分别描述一个被当前进程使用的文件。f_mode域表示文件将以何种模式创建。f_pos中包含下一次文件读写操作开始位置。f_inode指向描叙此文件的VFSinode,f_ops指向一组可以对此文件进行操作的函数入口地址指针数组。每当打开一个文件时,位于files_struct中的一个空闲文件指针将被用来指向这个新的文件结构。Linux进程希望在进程启动时至少有三个文件描述符被打开,它们是标准输入,标准输出和标准错误输出,一般进程会从父进程中继承它们。这些描述符用来索引进程的fd数组,所以标准输入,标准输出和标准错误输出分别对应文件描述符0,1和2。 小结Linux进程任务结构体task_structLinux的进程控制Linux进程调度进程的虚拟内存进程访问的文件 销售人员的58个误区 第1讲——没有找到有钱得客户经济基础决定上层建筑经济基础决定购买能力购买能力决定成交量成交量决定营销员得收入猪皮的故事肉联厂案例醒狮小区 第2讲——没有找到决定权的人找对人比找一堆人更重要!当出现这种现象要警惕:一拖再拖轻易答应态度极其和善没有拒绝问题 案例供电局双胞胎的保险成交案例 第3讲——不分青苹果红苹果只为一句承诺,空等白头!何谓青苹果何谓红苹果误区一味盯青苹果,错过很多红苹果一味盯青苹果,误事,伤身 正确方法正确的判断客户进行分类选择客户拜访的优先顺序设定青苹果客户的应对措施 案例客户与鱼的关系 第4讲—只推销自己熟的产品自我定位:货郎级结果:叫卖声高,回应寥寥 改变定位变货郎为医生!医生的描述:专业的形象专业的知识:产品,技能,专业的态度:帮助的心里专业的流程:检查,诊断,开药方 第5讲—无司工作忽略公司品牌,形象的宣传,不会借力!思考:客户担心什么?回答:太平洋的优势 第6讲—忘我工作买保险先买自己!案例95淮海战役 如何成功推销自己良好的形象精心的包装精心的准备无为的心态亲和力浓重的人情味 第7讲—守株待兔坐享其成只能等待失败!大树法则才能成功!寿险的成功——访量定江山! 第8讲—个人英雄主意不会利用客户推荐不与公司同步不会搭档展业 案例姚红红的影响中心我的保险伴侣 第9讲—主顾开拓不持续准客户枯竭导致英雄无用武之地!我们每天不能只想今天,更应该多想将来! 第10讲—跟着感觉走没有计划与目标就像开着没有舵的船!每年每月每天参照物 第11讲—拿着机枪当棒使产品不精,难能吸引客户案例20个好处 第12讲—一刀流少儿险,养老险,理财险,医疗险,统统一刀!案例一刀插在痛处'