操作系统-精髓与设计原理(第六版)读书笔记

来源:互联网 发布:数据库脱机和分离 编辑:程序博客网 时间:2024/05/18 04:03

本书封皮如下:




在china-pub上买了这本二手的操作系统精髓与设计原理,书很新,不过也不算厚,这和高教版那本操作系统概念显然不算是同一个类型的,讲的概念也都是一笔带过,没有做过多阐述,所以其实本书并不适合对操作系统一无所知的人,建议可以看看别的操作系统的书后再看这本书,这样可以事半功倍。


p82:进程的挂起,把进程放到磁盘从而可以释放内存空间供另一个进程使用
阻塞/挂起态:进程在外存中并等待一个事件
就绪/挂起态:进程在外存中,但是只要被载入内存就可以执行


p125:windows线程状态





p153-163:生产者/消费者问题
使用二元信号量解决无限缓冲区生产者/消费者问题

int n;binary_semaphore s=1,delay=0;void producer(){while(true){produce();semWaitB(s);append();n++;if(n==1){semSignalB(delay);}semSignalB(s);}}void consumer(){int m;semWaitB(delay);while(true){semWaitB(s);take();n--;m=n;semSignalB(s);consume();if(m==0){semWaitB(delay);}}}void main(){n=0;parbegin (producer,consumer);}



使用信号量解决无限缓冲区生产者/消费者问题
semaphore n=0,s=1;void producer(){while(true){produce();semWait(s);append();semSignal(s);semSignal(n);}}void consumer(){while(true){semWait(n);semWait(s);take();semSignal(s);consume();}}void main(){parbegin(producer,consumer);}





使用信号量解决有限缓冲区生产者/消费者问题
const int sizeofbuffer=/*缓冲区大小*/;semaphore s=1,n=0,e=sizeofbuffer;void producer(){while(true){produce();semWait(e)semWait(s);append();semSignal(s);semSignal(n);}}void consumer(){while(true){semWait(n);semWait(s);take();semSignal(s);semSignal(e);consume();}}void main(){parbegin(producer,consumer);}



使用管程解决有界缓冲区生产者/消费者问题
monitor boundedbuffer;char buffer[N]; //N个数据项空间int nextin,nextout; //缓冲区指针int count; //缓冲区数据项个数cond notfull,notempty; //为同步设置的条件变量void append(){if(count==n){cwait(notfull);}buffer[nextin]=x;nextin=(nextin+1)%N;count++;csignal(notempty);}void take(){if(count==0){cwait(notempty);}x=buffer[nextout];nextout=(nextout+1)%N;count--;csignal(notfull);}//管程体{nextin=0;nextout=0;count=0;}void producer(){char x;while(true){produce(x);append(x);}}void consumer(){char x;while(true){take(x);consume(x);}}void main(){parbegin(producer,consumer);}



使用消息解决有界缓冲区生产者/消费者问题
const int capacity=/*缓冲区容量*/;const int null=/*空消息*/;int i;void producer(){message pmsg;while(true){receive (mayproduce,pmsg);pmsg=produce();send(mayconsume,pmsg);}}void consumer(){message cmsg;while(ture){receive(mayconsume,cmsg);consume(cmsg);send(mayproduce,null);}}void main(){create_mailbox(mayproduce);create_mailbox(mayconsume);for(int i=0;i<=capacity;i++){send(mayproduce,null);}parbegin(producer,consumer);}


p193:
管道:有两类管道,命名管道和匿名管道。只有有“血缘”关系的进程才可以共享匿名管道,而不相关的进程只能共享命名管道。


p252:驻留集合管理
固定分配
-局部置换:一个进程的页框数是固定的;从分配给该进程的页框中选择被置换的页
-全局置换:不可能
可变分配
-局部置换:分配给一个进程的页框数可以不时地变化,用于保存该进程的工作集合;从分配给该进程的页框中选择被置换的页
-全局置换:从内存中的所有可用页框中选择被置换的页,这导致进程驻留集的大小不断变化


p304:粒度
细-单指令流中固有的并行-(指令)同步间隔<20
中等-在一个单独应用中的并行处理或多任务处理-同步间隔20-200
粗-在多道程序环境中并发进程的多处理器-同步间隔200-2000
非常粗-在网络节点上进行分布处理,以形成一个计算环境-同步间隔2000-1M
无约束-多个无关进程-不适用


p305
粗粒度线程:独立的模块,也称为系统,被分配到单独的处理器上
细粒度线程:许多相似或相同的任务可以由多个处理器同时处理
混合线程:采用可选择的配置,针对一些系统使用细粒度线程,针对另外一些使用粗粒度线程


p309:多处理器线程调度
负载共享:进程不是分配到一个特定的处理器,系统维护一个就绪进程的全局队列,每个处理器只要空闲就从队列中选择一个线程
组调度:一组相关的线程基于一对一的原则,同时调度到一组处理器上运行
专用处理器分配:通过把线程指定到处理器来定义隐式的调度
动态调度:在执行期间,进程中的线程数目可以改变


p315:实时调度
静态表法:执行关于可行调度的静态分析,分析结果为一个调度,用于确定在运行时一个任务必须开始执行
静态优先级抢占法:执行一个静态分析,但是没有制定调度,而且用于给任务指定优先级,使得可以使用传统的基于优先级的抢占式调度器
基于动态规划的调度法:在运行时动态地确定可行性,而不是在开始运行前离线地确定,一个到达的任务,只有当能够满足它的时间约束时,才可以被接受执行
动态尽力调度法:不执行可行性分析,系统试图满足所有的最后期限,并终止任何已经开始运行但错过最后期限的进程


p320:速率单调调度
任务周期T:该任务的一个实例到达到下一个实例到达之前的时间总量
执行时间C:每个发生的任务所需要的处理时间总量
处理器利用率U:C/T
为了满足所有期限,必须满足U1+U2+...+Un<=1
针对RMS,满足U1+U2+...+Un<=n*(2^(1/n)-1)


举例如下:
P1:C1=20,T1=100,U1=0.2
P2:C2=40,T2=150,U2=0.267
P3:C3=100,T3=350,U3=0.286
U1+U2+U3=0.753<3*(2^(1/3)-1)=0.779
故所有任务可以得到成功的调度


p321:优先级反转
当系统内的环境迫使一个较高优先级的任务去等待一个较低优先级的任务时,优先级反转就会发生。
避免无界限优先级反转方法
优先级继承:优先级较低的任务继承任何与它共享同一个资源的优先级较高的任务的优先级,当高优先级的任务在资源上阻塞时,优先级立即更改,当资源被低优先级的任务释放时这个改变结束
优先级置顶:优先级与每个资源相关联,资源的优先级被设定为比使用该资源的具有最高优先级的用户的优先级要高一级。调度器然后动态地将这个优先级分配给任何访问该资源的任务,一旦任务使用完资源,优先级返回到以前的值


p327:windows调度-处理器的调度单位为线程
进程基本优先级时进程对象的一个属性,它可以取从0到15的任何值,与进程对象相关联的每个线程对象有一个线程基本调度优先级属性,表明该线程相对于该进程的基本优先级。线程的基本优先级可以等于它的进程的基本优先级,或者比它进程的基本优先级高2级或低2级。
一旦一个可变优先级类中的线程被激活,它的实际优先级称作该线程的当前优先级,可以在给定的范围内波动,当前优先级永远不会低于该线程的基本优先级的下限。


p361:windows异步I/O
四种不同技术在I/O完成时发信号
给一个文件对象发信号:当在某个设备对象上的操作完成时,与该设备对象相关联的一个指示器被置位,请求该I/O操作的线程可以继续执行,直到它到达某一时刻必须等待I/O的操作完成
给一个事件对象发信号:允许在一个设备或文件中同时有多个I/O请求,线程为每个请求创建一个事件,随后该线程可以在这些请求中的一个上或者请求的集合上等待
异步调用过程:利用与线程相关联的一个队列,线程产生I/O请求,指定一个用户态的例程,当I/O完成后来回调它
I/O完成端口:应用程序创建一个线程池来处理I/O请求的完成,每个线程都在完成的端口上等待,I/O端口完成后,内核唤醒线程来继续进行相应处理
轮询:异步I/O请求会在操作完成时向进程用户的虚拟内存中写入状态和数据的计数,线程检查该值知道操作是否已经完成


p483:客户/服务器应用程序分类
基于主机的处理:传统的大型机环境,所有处理都是在一台中心主机上完成的
基于服务器的处理:客户端主要负责提供图形用户界面,所有处理都是在服务器上完成的
基于客户的处理:所有应用的实际处理可能全部都在客户端完成
合作处理:应用处理以最优化的方式来执行


p484:三层客户/服务器结构
用户机器,中间层服务器,后端服务器。中间层服务器基本上是位于用户客户和很多后端数据库服务器之间的网关


p492:集群
集群方法:
被动等待:当主服务器出现故障时,由从服务器来接管
活跃主机:从服务器也能用于任务处理
独立服务器:各服务器具有独自的磁盘,数据可连续地从主服务器复制至从服务器
各服务器连接到磁盘:所有服务器都连接到同一磁盘,但每台服务器仍拥有自己的磁盘,一旦某台服务器发生故障,其磁盘被其他服务器接管
服务器共享磁盘:多台服务器同时共享对磁盘的访问


p505:Dekker算法
boolean flag[2];int turn;void P0(){while(true){flag[0]=true;while(flag[1]){if(turn==1){flag[0]=false;while(turn==1)//do nothingflag[0]=true;}}//critical sectionturn=1;flag[0]=false;}}void P1(){while(true){flag[1]=true;while(flag[0]){if(turn==0){flag[1]=false;while(turn==0)//do nothingflag[1]=true;}}//critical sectionturn=0;flag[1]=false;}}void main(){flag[0]=false;flag[1]=false;turn=1;parbegin(P0,P1);}



p506:Peterson算法
boolean flag[2];int turn;void P0(){while(true){flag[0]=true;turn=1;while(flag[1]&&turn==1)//do nothing//critical sectionflag[0]=false;}}void P1(){while(true){flag[1]=true;turn=0;while(flag[0]&&turn==0)//do nothing//critical sectionflag[1]=false;}}void main(){flag[0]=false;flag[1]=false;parbegin(P0,P1);}


后记:我觉得操作系统除了这些理论知识外还应该深入了解一门操作系统,例如windows或者linux或者unix,只有从头到尾彻底理解一个操作系统才更具有实践意义和价值,理论也许每个人都懂,但要分场合。例如上周面试时面试官问我消息同步用到什么机制,我说有一个信箱,他说确实有这么一个概念,问我是哪个操作系统里面用到的,我居然告诉他windows,他哈哈大笑,说windows早就把这种信箱机制给废了。实在很囧,理论不联系实际,又有何用?我知道有这么回事,但不知道具体是用在哪个环境中的,对程序员来说,这实在是太凄凉了吧。

原创粉丝点击