操作系统学习笔记三进程

3.1进程概念

        进程与作业称谓上的不同

1进程

        进程是执行中的程序,这只是非正式的说法。进程不只是程序代码,还包括当前活动,通过程序计数器的值和处理器寄存器的内容来表示。此外,进程还包括进程堆栈段(临时数据、函数参数、局部变量、地址)和数据段(包括全全局变量。还可能包括堆(leap),是动态分配的内存。

        进程是一个活动实体,他有一个程序计数器来表示要执行的命令和相关资源集合。虽然两个进程与同一程序相关,如同一用户调用的不同web浏览器副本,但他们是独立的进程。尽管代码段相同的,但数据段、堆栈等却不同。

2.进程状态

       一次只有一个进程可以在一个处理器上运行,但多个进程可以处于就绪或等待状态。

3.进程控制块

        进程在操作系统内有进程控制块(process control block,PCB)来表示,PCB包含了进程状态、计数器、cpu寄存器、cpu调度信息、内存管理信息、记账信息等信息

4.线程

        一个进程是一个只能进行单个执行线程的程序

3.2进程调度

        多道程序设计的目的是无论何时都有进程执行,从而使cpu利用率达到最大。分时系统的目的是在进程之间快速切换cpu以便用户在程序运行时能与其进行交互。为达到这一目的,进程调度选择一个进程到cpu上执行。

1.调度队列

       进程进入系统时被加入到作业队列中,该队列包含系统中所有进程。驻留在内存中等待运行的程序保存在就绪队列中,该队列常用链表来实现,其头节点指向链表的第一个和最后一个PCB块的指针。每个PCB包括一个指向就绪队列的下一个PCB的指针域。

 

在linux 中每一个进程都由task_struct 数据结构来定义. task_struct就是我们通常所说的PCB。例如,进程的状态就是通过这个结构中的long state字段来表示的。(http://baike.baidu.com/view/396362.htm

 

         操作系统也有其他队列。等待特定IO设备的进程列表称为设备队列。每个设备都有自己的设备队列。

         讨论进程调度的常用方法是队列图。新进程开始处于就绪队列,当进程分配到cpu执行时,可能发生

           a.进程发出一个IO请求,并放到IO队列中。

           b.进程创建新的子进程,并等待其结束

           c.进程由于中断而强制释放cpu,并被放回到就绪队列中

3.3调度程序

         进程会在各种调度队列之间迁移,操作系统必须从这些队列中选择进程。进程的选择是由相应的调度程序(scheduler)来执行的。

         通常批处理系统中,进程更多的是被提交,而不是马上执行。这些进程通常放到磁盘的缓冲池里,以便以后执行。长期调度程序或作业调度程序从该池中选择进程,并装入内存以准备执行。短期调度程序或cpu调度程序从准备执行的进程中选择进程,并为之分配cpu。

          这两个调度程序的主要差别是调度的频率,短期调度程序通常100ms至少执行一次,长期调度程序执行的并不频繁。长期调度程序控制多道程序设计的程度(内存中进程的数量)。长期调度程序必须仔细选择执行进程,IO为主的进程通常比执行计算花费更多时间。为使系统达到平衡和更好的性能,长期调度程序应当选择一个合理的包含IO为主的和cpu为主的组合进程以充分使用设备和短期调度程序。

  对于linux和windows系统通常没有长期调度程序,这些系统的稳定性依赖于物理限制,如果系统性能下降很多,会有用户的退出。  有的系统如分时系统,可能引入中期调度程序,其核心思想是能够将进程从内存中移出,这有必要实行交换,将在第八章讨论。

3.3上下文切换

   中断使cpu从当前任务改变为运行内核子程序。当发生一个中断时,系统需要保存当前运行在cpu中进程的上下文,从而能在其处理完后恢复上下文。进程的上下文用PCB来表示。通常通过执行一个状态保存(state save)来保存cpu当前状态,之后执行一二个状态恢复(state restore)重新开始运行。

         cpu切换到另一进程需要保存当前状态并恢复另一进程状态,这叫做上下文切换(context switch)。其时间与硬件支持密切相关。

3.3进程操作

1.进程创建

           进程在执行时,能通过创建进程系统调用穿件多个新进程。创建进程为父进程,而新进程叫做子进程。新进程都可再创建其他进程,从而形成了进程树。

            下面是一个典型的Solaris系统的进程树

       

            大多数操作系统根据一个唯一的进程标识符(process indentifier,pid)来识别进程,pid通常是一个整数值。

            在UNIX中,使用ps命令可以得到一个进程列表。

            通常进程需要一定的资源来完成其任务。子进程被创建是,子进程直接从操作系统或间接从父进程那里获取资源。在进程创建时,初始化数据有父进程传给子进程,进程被创建时,有两种执行可能:

          s.父进程与子进程并发执行  b.父进程等待,直到子进程执行完

           UNIX中,每个进程用唯一整数标识符来标识,通过fork()调用,可创建新进程,新进程通过复制原来进程的地址空间而成。这种机制允许父子进程之间方便的通信。通常系统调用fork后,一个进程会使用系统调用exec(),以用新程序来取代进程的内存空间。系统调用exec()将二进制文件装入内存,并开始执行。采用这种方式,两个进程都能相互通信,并按各自的方式执行。

          下图的c程序说明了上述的UNIX调用

                

             现有两个不同的进程运行同一程序,子进程的pid值为0.父进程的pid值大于0.子进程通过系统调用execlp(),用UNIX命令/bin/ls来覆盖其地址空间。父进程通过系统调用wait()来等待子进程的完成。当子进程完成时(通过调用exit()),父进程会从wait()调用处开始继续,并调用exit()以表示结束。

            再如,windows的进程生成,WIN32 API通过CreatProcess()创建进程,然而fork的子进程继承了父进程的地址空间,下面的程序生成了一个装载mspaint.exe应用程序的子进程,选择10个参数的默认值传给 creatprocess().

      

2进程终止

   进程执行完最后的语句并使用系统调用exit()请求系统删除自身时,进程终止。

3.4进程间通信

   按进程是否与其他进程共享数据,可分为独立的和协作的,可能需要提供环境以允许进程协作,理由如下:

   1.信息共享2.提高运算速度3.模块化4.方便

   协作进程需要一种进程间通信机制(interprocess communication,IPC)来允许进程相互交换数据与信息。有两种模式共享内存和消息传递。

  一、共享内存系统

               需要建立共享内存区域,可以研究一下生产者—消费者问题。生产者进程产生信息以供消费者进程消费。例如,编译器产生的汇编代码供汇编程序使用,而汇编程序反过来产生目标代码供连接和装入程序使用。采用共享内存是解决生产值——消费者问题方法之一。为允许生产者进程和消费者进程能并发执行,必须有一个缓冲来被生产者填充并被消费者所使用。此缓冲驻留在共享内存区域,消费者使用一项时,生产者能产生另一项。

               可以使用两种缓冲。无限缓冲对缓冲大小没有限制。消费者可能不得不等待新的项,但生产者总可以产生新的项。有限缓存假设缓存大小固定。

                # define BUFFER-SIZE 10

 

                 typedef struct     {

                 ...

                 }  item;

               

                  item buffer[BUFFER-SIZE];

                  int  in=0;

                  int out=0;

                 共享缓存通过循环数组和两个逻辑指针in和out来实现,in指向缓冲中下一个空位;out指向缓冲中第一个满位。当in==out时,缓冲为空;当(in+1)%BUFFER-SIZE==out时,缓冲为满。

              生产者和消费者代码如下:生产者进程有一个局部变量nextProduced以储存所产生的新项。消费者有一个局部变量nextConsumed以存储要使用的新项。

             这种方法允许缓存的最大项数是 BUFFER—SIZE-1

  二、消息传递系统

     消息传递提供一种机制以允许进程不必通过共享地址空间来实现通信和同步,这在分布式系统中很有用。例如用于WWW的chat程序就是通过信息交换来实现通信。

                   如果进程P和Q需要通信,他们之间要有通信线路(communication link).这里只讨论逻辑实现。下面是一些逻辑线路和接收/发送操作的方法:

                    直接或间接通信;同步或异步通信;自动或显式缓冲

                   下面研究这些相关问题

                     1.命名

                      直接通信:每个进程必须明确的命名通信的接受者或发送者,定义如下:

                       send(P,message)发送信息到进程P

                       receive(Q,message)接收来自Q的消息

                       这种方案的通信每对进程自动建立线路,一个线路仅与两个进程相关,每对进程之间只有一个线路,采用对称寻址即通信双方须命名对方以便通信。

                       这种方案的一种变形采用非对称寻址即只要发送者命名接受者

                        send(P,message)发送消息到进程P     

                        receive(id,message)接收来自任何进程的消息,变量id设置成与其通信的进程名称

                        对称和非对称寻址的缺点是限制了进程定义的模块化

                      

                         间接通信,通过邮箱或端口发送和接收消息。邮箱可以抽象为一个对象,每个邮箱有唯一的标识符。一个进程可能通过许多不同的邮箱与其他进程通信。

                         send(A,message)发送一个消息到邮箱A

                         receive(A,message)接收来自邮箱A的消息

                          对于这种方案,通信线路有如下属性:两个进程之间可有不同的线路,每个线路对应一个邮箱;一个线路可以与两个以上的进程相关联。

                       

                        2.同步

                          消息传递可以是阻塞或非阻塞——也称为同步或异步。

               send和receive可以是阻塞或非阻塞的。当都阻塞时,则接受者和发送者之间就有一个集合点(rendezvous)。当使用阻塞send和receive时,如何解决                      生产  者  和消费者问题就不在重要了。生产者仅需要调用阻塞send()并等待,直到消息被送到进程或邮箱。

                   

                 3.缓冲

                  通信进厕所交换的消息都驻留在临时队列中,队列实现有三种方法。

                  零容量:队列的最大长度为0.线路中不能有消息处于等待,对于这种情况,消息必须阻塞发送,直到接受者接收到消息。

                  有限容量:最多有n个消息驻留在其中,线路满,阻塞发送者

                   无限容量

3.5IPC系统实例

          1.POSIX 共享内存

            首先使用shmget()创建共享内存段。

             segment-id=shmget(IPC_PRIVATE,size,S_IRUSR | S_IWUSR);

                                     共享内存段标识符    内存大小          标识模式,指定如何使用内存段:读出或写入

            想访问共享内存段的进程必须采用shmat()系统调用来将其加入地址空间,其需要三个参数。

            一旦共享内存区域被加入到进程的地址空间,进程就可以采用从shmat()返回的指针,作为一般的内存访问来访问共享内存。           

            当一个进程不再需要访问共享内存段,可按照下面方法将共享内存的指针传给系统调用shmdt():

             shmdt(shared-memory)

             最后可以采用系统调用shmctl()删除共享内存段。

              下图演示了:生成4096B的共享内存段,一旦共享内存被加入,进程向其中写入消息“hi,there”,输出后,他被删除共享内存区域。

2.实例:Mach

           系统中绝大多数通信是通过消息传递的。每个任务创建时,也创建了两个特别的邮箱:内核邮箱和通报邮箱(notify)。消息传输需三个调用:msg-send() 发送消息,msg_receive()接受信息。远程过程调用(RPC)通过msg_rpc() 执行,它发送消息并等待来自发送者的一个返回消息。RPC模拟了典型的子程序过程调用,但他还能在系统之间工作——这就解释了远程。

            系统调用port-allocate()创建新邮箱并为其消息队列分配空间,消息队列默认最大长度8个消息。

3.实例:windows XP

           XP的消息传递工具称为本地过程调用(LPC) 工具,他为同一机器的两个进程之间通信  

3.6客户机—服务器系统通信

1.Socket

  Socket(套接字)可定义通信的端点。一对通过网络通信的进程需要使用一对Socket,每个进程各一个。Socket由IP地址与一个端口号连接组成。服务器通过监听指定端口来等待客户请求。一旦收到请求,服务器就接收来自客户SOcket的连接。服务器实现特定功能如telnet、ftp、http。。所有低于1024的端口被认为是众所周知的,用来实现标准服务。

 

    客户机进程发出连接请求时,他被主机赋予一个大于1024的某个端口。

2.远程过程调用

   3.5介绍的RPC方式许多方面类似于3.4节IPC机制 。但用于RPC交换的消息有很好的结构,因此不再仅仅是数据包。

   端口只是一个数字 ,并包含在消息包的开始处,虽然一个系统通常只有一个网络地址,但他在这一地址内有许多端口号以区分所支持的多种网络服务。RPC语义允许客户机调用位于远程主机上的过程。许多RPC系统定义了数据的机器无关表示。一种这样的表示称为外部数据表示(XDR)。在客户机端,参数编组涉及将机器有关数据再被发送到服务器端之前编组成XDR,在服务器端,XDR转换成服务器所用的机器有关表示。

  一个重要的事项是调用的语义,处理该问题的一种方法是操作系统确保一个消息刚好执行一次,而不是最多执行一次。

  另一个重要事项是RPC方案要求客户机和服务器之间有类此绑定的一种关系。但客户机如何知道服务器的端口呢?一个系统无法拥有另一个系统的所有信息,因为他们无法共享内存。第一种方法,绑定信息以固定端口地址形式预先固定。第二种方法,绑定通过集合点机制动态的进行。通常操作系统会在一个固定的RPC端口上提供集合点服务程序。客户机程序发送一个包括PRC的名称的消息给集合点服务程序,以请求他所执行的RPC端口地址。

3.远程方法调用

   远程方法调用(remote method invocation,RMI)是一个类似的java特性。RMI允许线程调用远程对象的方法。如果对象位于不同的JVM上,那么就认为是远程的。

   RMI与PRC在两方面有根本不同。一、RPC支持子程序编程,即只能调用远程的子程序或函数。而RMI是基于对象的,他支持调用远程对象的方法。二、RPC中,远程过程的参数是普通数据结构,RMI可以将对象作为参数传递给远程方法。

   为了使远程方法对客户机和服务器透明,RMI采用存根(stub)和骨干(skeleton)实现远程对象。存根为远程对象的代理,他驻留在客户机中。当客户机调用远程方法时,远程对象的存根被调用。这种客户端存根负责创建一个包,它具有服务器上要调用方法的名称和用于该方法的编排参数。存根将该报发送给服务器,远程对象的骨干会接受他。骨干负责重新编排参数并调用服务器上要执行的方法。骨干接着编排返回值,然后打包,并将该包返回给客户机。存根重新编排返回值,并传给客户机                   

7小结

RPC是另一种形式的分布式通信。当一个进程调用远程的方法时,就出现了RPC。RMI是RPC的java版。

 

 

    

             

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值