这学期学了门操作系统,看到大家上课后感觉很困难,所以想整理点东西帮助大家总结。
进程:a program in execution从前:单进程现在:多进程即通过CPU的多路复用使得同时执行多个进程。
进程分为用户进程和系统进程。在进程之前,其实作业才是第一个被提出来的,用于批处理系统中。批处理系统术语:提交作业。分时系统术语:任务。任务和作业都类似于进程。只是称呼不同罢了。
进程包括了许多东西,在内存中一个进程有文本段(放代码的地方)、数据(放全局变量)、堆(动态分配的数据,堆是向上伸展)、栈(局部变量、函数参数,栈是向下伸展的)。进程和程序的区别:程序(exe)、进程是活动的即包含PC。当程序被load进memory时,就成了进程。当多个进程与一个程序相关时,他们是单独的进程,共享文本段,栈、堆等各自独立。
进程在OS中状态想像成一张图,new、running、ready、waiting、terminate.
waiting状态是指进程要执行I/O,则被调入I/O设备的等待队列等待。
ready则是在内存中的就绪队列中。但是记住一个处理器只能running一个进程,但是能有多个进程在等待和就绪队列中。
就绪队列听名字就很形象,不多说了。要说的是他在内存中。每个device都有一个队设备列,链表存放。进程在OS中以PCB方式存在。再讲下PCB的结构,PCB很复杂,但是能够实现很多功能,不必全部死记硬背。(0)pid
(1)进程状态。(2)PC.指向下一个PCB。(3)CPU寄存器。存放变量,堆栈指针。(4)CPU调度信息。PCB的优先级,调度指针。(5)内存管理信息:base&limit寄存器,页表段表。(6)记账信息。用的时间,用了多少内存等等。(7)I/O状态。对应I/O设备的状态。打开的文件。
multiprogramming通过一个程序接一个程序的执行,把最宝贵的CPU时间填满。timesharing通过把一个CPU时间分成时间片,平均分给用户,与用户交互,使得用户感觉像一个人单独用机器.
linux 是以C的struct来实现PCB的。
进程进入CPU后可能会有4种情况:
1.I/O请求进入设备队列。
2.产生子进程而进入就绪队列。
3.发生中断被迫停止。
4.顺利执行完。
批处理系统中,进程被放入磁盘的缓冲池中,当需要被用到时,就导入内存,这个成为长期调度程序。可以控制多道程序的degree(你想哦,多道程序的特点是一次导入多个进程进入内存,目的是将CPU的时间塞满。)从内存中选择进程导入CPU的程序称为短期调度程序,频繁执行。
进程分为:I/O为主(大多数PCB都是在设备队列中),CPU为主(大多数PCB用于执行计算)。长期调度需要选择合理的组合进内存。UNIX/Windows没有长期调度程序。直接把进程放入内存,但是会出现灾难,所以引入了medium-term schedular。分时系统中,引入了中期调度程序:可以将某些进程从内存中移出,到某时可以再导入,从中断处继续执行,这个也称为swapping。
上下文切换:就是PCB的保存与恢复。保存旧进程的PCB,并放入新进程。如果是多组寄存器集合,则可以一些寄存器保存一个进程的状态,那么上下文切换可以简单地改变寄存器的指针即可。
进程树:一个进程在执行时能创建新的进程,新的进程又能再创建新的进程,形成了进程树。pid用来标识每个进程。子进程可以共享父进程的资源也可以从OS那拿资源。但是共享父进程资源能够限制资源的分配。父进程与子进程可以并发执行也可以先执行子进程再执行父进程。
UNIX中(1)fork()创建进程,子进程调用时返回0,父进程返回子进程的pid。(2)exec():执行。(3)wait():父进程等待。(4)exit():退出。
进程执行exit ()后就终止了,并释放资源。
子进程终止后,pid要返回给父进程,父进程就知道哪个子进程结束了。父进程可以也通过系统调用终止子进程。
级联终止:父进程终止导致子进程被迫终止。
进程分为独立的和协作的。协作进程在后面进程同步时会提到。
进程通信IPC1.共享内存。传输速度快,只在创建共享区域时使用系统调用,其余时刻都是正常的内存访问。
2.消息传递。用于交换较少数据。通过send和receive来发送和接受消息,这样就不必共享内存。两者的数据格式都没有严格规定。
有限缓冲:缓冲的大小固定。
无限缓冲:缓冲的大小无限。
共享内存用于解决生产者消费者模型的问题,需循环队列缓冲,加入变量count可以解决缓冲项数只有BUFFER_SIZE-1的问题。服务器代码:while(true){ while((in+1)%BUFFER_SIZE==out); buffer[in]=new; in=(in+1)%BUFFER_SIZE; }客户端代码:while(true){ while(in==out); new=buffer[out]; out=(out+1)%BUFFER_SIZE;}
消息传递,有OS提供,分布式环境中。如果要使两个进程进行消息传递,必须要有通信线路。直接通信:send和receive的参数直接说明接受者和发送者的对象名,只要调用函数,则自动创建链路,并且一个线路只能有两个进程。间接通信:通过第三方(邮箱)为暂存。两个进程之间可以有多条线路(即多个邮箱)。一个邮箱可以有多个进程共享。邮箱挺像共享内存。对于send和receive的执行方法(面对模棱两可时),通过算法实现,没有特定要求。
邮箱的拥有者:
1.进程。则要确定拥有者和使用者。邮箱存在进程的地址空间中,当进程终止,则邮箱也终止。2.OS。不属于特定进程。创建新邮箱的进程默认为邮箱的拥有者。
阻塞某功能:某功能一执行,就不能再执行该功能。非阻塞某功能:相反。
消息传递缓冲队列:1.0容量。2.有限。3.无限。
/*---------------------------------------------------------------------------------------------------------------
在定义通信的时候,有没有想过就算知道对象,但是是怎么确定线路,最后找到目标的呢。?命名问题也比较重要。1.broadcasting2.forward pointer 多级搜索3.home-based approach (1)one-tiered scheme:每次查找都通过home的集中营去找(2)two-tiered scheme:先在本地找,如果找不到,则在home中找。4.distributed hash tables:chord system . 用环状的hash表。但是不能保证原有的物理位置。name resolution:根据name 找到address。Name linking:hard link或者soft link。namespace的实现:hierarchy
-------------------------------------------------------------------------------------------------------------------*/来讲客户服务器模型的另外3种通信方法。
1.socket。socket是成对出现的。一个socket是ip地址+端口号组成。服务器始终监听各个端口号,当客户发出请求时,他会与服务器监听的端口号相匹配进行通信。但是Socket只允许交换的是无结构的字节流。RMI就可以通过实现序列化--------------------------------------------------------------------------------------------------------------------------
java提供了Socket类
Socket类实现TCPsocket;DatagramSocket类实现UDPsocket;socket还可以多播发送。
import java.net.*;import java.io.*;
public class DataServer{ public static void main(String[]args) { try{ ServerSocket sock=new ServerSocket(6013); while(true) { Socket client=sock.accept(); PrintWriter pout=new PrintWriter(client.getOutputStream(),true); pout.println(new java.util.Data.toString()); client.close(); } } catch(Exception e) { System.err.println(e); } }}
PrintWriter能够使服务器能直接利用println发送给客户。
import java.net.*;import java.io.*;public class DataClient{ public static void main(String[]args) { try { sock=new Socket("127.0.0.1",6013); inputStream in=sock.getInputStream(); BufferReader bin=new BufferReader(new InputStreamReader(in)); String line; while((line=bin.readLine())!=NULL) { System.out.println(line); } sock.close(); } catch(Exception e) { System.err.println(e); } }}
--------------------------------------------------------------------------------------------------------------------------2.RPC数据有很好的结构。客户发出要执行的函数,在服务器端执行完后,把结果返回给客户。RPC的目的是为了让客户调用服务器像调用本地一样。存根只是一个接口。XDR(外部数据表示):用来统一客户端和服务器的数据表示形式。必须确保RPC数据传送的唯一性。即只能传一次(ack解决)对于绑定服务与客户,有两种方法:第一种是端口固定。第二种是通过集合点来绑定(先访问集合点请求端口号,再等待返回端口号)。3.RMI java中的RPC如果对象位于不同的JVM,则称为远程。因此可以在一台机器开多个JVM进行模拟通信,打开一个命令行就说明打开一个JVM。
客户端保留存根(远程方法的接口),本地参数可以是任何继承了java.io.serializable的接口类。注意,远程对象都要继承remote类,每个远程方法要throws remoteException。只有远程方法才能引用。RMI VS RPC1.RMI的数据结构是对象,调用远程的对象方法。RPC支持子程序编程。2.RMI的参数是对象,RPC是普通的数据结构。
RMI采用存根(在客户机)和骨干(服务器)。其实骨干就是存根。