- 博客(133)
- 收藏
- 关注
原创 操作系统之保护模式
* 问题1:为什么会有保护模式**实模式下操作系统和用户程序属于同一特权级用户程序所引用的地址都是指向真实的物理地址用户程序可以自由修改段基址,可以访问所有内存以上三个原因属于安全缺陷访问超过64KB的内存区域时要切换段基址一次只能运行一个程序,无法充分利用计算机资源共20条地址线,最大可用内存为1MB为了克服这种恶劣的内存管理方式,处理器厂商开发出保护模式,这样,物理内存地址不能直接被程序访问,程序内部的地址(虚拟地址)需要被转化为物理地址后再去访问。
2022-10-25 15:47:10
1053
1
原创 操作系统实现——编写MBR
由于MBR是占据了硬盘的第0扇区(以逻辑LBA方式,扇区从0开始编号,若是以物理CHS方式,扇区则从1开始编号),第一扇区是空闲的,可以用,但离得太近了,所以把loader放到第2扇区,MBR从第2扇区中把它读出来,读出来放到哪?第一条指令中的源操作数0x18是立即数,目的操作数ax是寄存器,所以它既是立即数寻址,也是寄存器寻址,第二条指令中,源操作数和目的操作数都是寄存器,所以纯粹是寄存器寻址。0x1234是段偏移地址,默认的段地址是DS,这条指令是将内存地址DS:0x1234处的值写入ax寄存器。
2022-10-15 14:51:55
1287
原创 Thread类的封装
C编程风格:注册全局函数到网络库,然后通过函数指针进行回调面向对象风格:用一个类继承一个抽象类,实现接口的具体业务逻辑基于对象风格:用一个类包含一个具体类对象,在构造函数中用bind来注册成员函数。...
2022-08-13 16:40:53
913
1
原创 深入理解红黑树
AVLtree是一个加上了额外条件的二叉搜索树,其平衡条件的建立是为了确保整棵树的深度为O(logN),直观上的最佳平衡条件是每个节点的左右子树有着相同的高度,我们很难保证插入新元素而又保持这样的平衡条件,AVLtree于是退而求其次,要求任何节点的左右子树高度相差1,这是一个较弱的条件,但任然能保证对数深度平衡条件。假设我们为RB-tree分别插入3,8,35,75,根据二叉搜索树的规则,这四个新节点的落脚点应该如图所示,它们都破坏了RB-tree的规则,因此我们必须调整树型。...
2022-07-23 14:50:45
132
原创 深入理解heap
completebinarytree整棵树内没有任何节点漏洞,这带来一个极大的好处我们可以利用array来存储所有节点,假设动用一个小技巧,将array的#0元素保留,那么当completebinarytree中的某个节点位于array的i处时,其左节点必位于array的2i处,其右节点必位于array的2i+1处,其父节点必位于i/2处(此处的"/‘’权且代表高斯符号,取其整数),这种通过array表述tree的方式,我们称为隐式表述法。下面是pop_heap算法的实现细节。...
2022-07-20 18:40:25
206
原创 深入理解deque
deque是一种双向开口的连续线性空间,所谓双向开口,意思是可以在头尾两端分别做元素的插入和删除操作,如图所示deque允许常数时间内对起头端进行元素的插入和删除操作,deque没有所谓容量观念,因为它是动态地以分段连续空间组合而成,随时可以增加一段新的空间并链接起来,因此,deque没有必要提供所谓的空间保留功能虽然deque也提高RamdonAccessIterator,但它的迭代器并不是普通指针,这影响了各个运算层次,因此,除非必要,我们应尽可能选择使用vector而非deque。...
2022-07-19 17:54:51
653
原创 深入理解list
相较于vector的连续线性空间,list就复杂很多,它的好处是每次插入或者删除一个元素,就配置或释放一个空间,因此,list对于空间的运用有绝对的精准,一点也不浪费以下是STLlist的节点结构:由于STL list是一个双向链表,迭代器必须具备前移,后移的能力,所以list提供的是Bidirectional iteratorslist有一个重要性质:插入操作和接合操作都不会造成原有的list迭代器失效,list的元素删除操作也只有“指向被删除元素”的那个迭代器失效list迭代器的设计list的数据
2022-07-14 16:28:43
407
原创 深入理解vector
vector的数据安排以及操作方式与array非常相似,两者的唯一差别在于空间的运用的灵活性,array是静态空间,一旦配置了就不能改变,vector是动态空间,随着元素的加入,它的内部机制会自行扩充空间以容纳新元素vector维护的是一个连续线性空间,所以不论其元素型别为何,普通指针都可以作为vector的迭代器而满足所有必要条件,所以vector提供的是Random Access Iteratorsvector的数据结构vector所采用的数据结构非常简单:线性连续空间。它以两个迭代器start和f
2022-07-13 12:22:22
229
原创 深入理解迭代器
不论是泛型思维或STL的实际运用,迭代器都扮演着重要的角色,STL的中心思想在于:将数据容器和算法分开,彼此独立设计,最后再以一贴胶着剂将他们聚合在一起以find()函数为例,它接受两个迭代器和一个"搜寻目标"迭代器是一种行为类似指针的对象指针的最常用也最重要的编程工作就是对operator*和operator->进行重载工作,比如:迭代器相应型别假设算法中有必要声明一个变量,以迭代器所指对象的型别为型别,如何实现?解决办法是:利用function template的参数推导机制,例如:我们以
2022-07-11 18:14:23
636
原创 C++11半同步半异步线程池
在处理大量并发任务的时候,如果按照传统的方法一个请求一个线程来处理请求任务,线程的创建和销毁将消耗过多的系统资源,还增加了线程上下文切换的开销,线程池技术可以很好的解决这些问题,线程池技术通过在系统中预先创建一定数量的线程,当任务请求到来的时候从线程池中分配一个预先创建的线程去处理任务,线程在处理完任务以后还可以重用,通过线程池能避免大量的线程创建和摧毁动作线程池分为半同步半异步线程池和领导者追随者线程池,本文主要通过C++11实现一个半同步半异步的线程池半同步半异步的线程池分为3层:第一层是同步服务层
2022-07-08 19:53:01
459
原创 C++11实现观察者模式
这种实现方式限制太多,最主要的两个限定是:第一,需要继承,继承是强对象关系,不够灵活,第二,观察者模式被通知的接口参数不支持变化,导致观察者不能应付接口的变化。c++11实现的观察者模式,内部维护了一个泛型函数列表,观察者只需要将观察者函数注册进去即可,通知接口使用了可变参数模板,支持任意参数,消除了接口变化的影响...
2022-07-06 17:47:43
577
1
原创 分页系统中的设计问题
分页系统中的设计问题局部分配策略与全局分配策略负载控制页面大小分离的指令空间和数据空间共享页面共享库内存映射文件清除策略虚拟内存接口我们将讨论为了使分页系统达到较好的性能,操作系统设计者必须仔细考虑的一些其他问题局部分配策略与全局分配策略怎样在相互竞争的可运行进程之间分配内存如图a所示,三个进程A、B、C构成了可运行进程的集合。假如A发生了缺页中断,页面置换算法在寻找最近最少使用的页面时是只考虑分配给A的6个页面呢?还是考虑所有在内存中的页面?如果只考虑分配给A的页面,生存时间值最小的页面是A5,
2021-09-11 19:28:38
393
原创 页面置换算法
页面置换算法最优页面置换算法最近未使用页面置换算法先进先出页面置换算法第二次机会页面置换算法时钟页面置换算法最近最少使用页面置换算法用软件模拟LRU工作集页面置换算法工作集时钟页面置换算法总结最优页面置换算法该算法是这样工作的:在缺页中断发生时,有些页面在内存中,其中有一个页面(包含紧接着的下一条指令的那个页面)将很快被访问,其他页面则可能要到10、100或1000条指令后才会被访问,每个页面都可以用在该页面首次被访问前所要执行的指令数作为标记这个算法惟一的问题就是它是无法实现的。当缺页中断发生时,操
2021-09-09 17:58:05
692
原创 深入理解虚拟内存
虚拟内存虚拟内存的产生虚拟地址的实现分页MMU的实现页表加速分页的过程转换检测缓冲区虚拟内存的产生尽管基址寄存器和界限寄存器可以用于创建地址空间的抽象,还有另一个问题需要解决:管理软件的膨胀(bloatware)需要运行的程序往往大到内存无法容纳,而且必然需要系统能够支持多个程序同时运行,即使内存可以满足其中单独一个程序的需要,但总体来看,它们仍然超出了内存大小。交换技术 (swapping)并不是一个有吸引力的解决方案,因为一个典型的SATA磁盘的峰值传输率最高达到 100MB/s,这意味着至少需要
2021-09-07 20:37:18
248
原创 存储器抽象:地址空间
地址空间地址空间概念基址寄存器与界限寄存器交换技术空闲内存管理使用位图的存储管理使用链表的存储管理地址空间概念要保证多个应用程序同时处于内存中并且不互相影响,则需要解决两个问题:保护和重定位,我们来看 一个原始的对前者的解决办法,它曾被用在IBM 360上:给内存块标记上一个保护键,并且比较执行进程的键和其访问的每个内存字的保护键。然而,这种方法本身并没有解决后一个问题,虽然这个问题可以通过在程序被装载时重定位程序来解决,但这是一个缓慢且复杂的解决方法一个更好的办法是创造一个新的内存抽象:地址空间。就
2021-08-31 20:15:18
770
原创 经典的IPC问题
经典的IPC问题哲学家就餐问题读者-写者问题哲学家就餐问题如图所示:哲学家有两种交替状态:吃饭和思考,当一个哲学家觉得饿了时,他就试图分两次去取其左边和右边的叉子,每次拿一把,但不分次序。如果成功地得到了两把叉子,就开始吃饭,吃完后放下叉子继续思考。关键问题是:能为每一个哲学家写一段描述其行为的程序,且决不会死锁吗?如图所示,给出了一种直观的解法,过程take_fork将一直等到所指定的叉子可用,然后将其取用。不过,这 种显然的解法是错误的。如果五位哲学家同时拿起左面的叉子,就没有人能够拿到他们
2021-08-30 16:43:24
810
原创 不同系统的调度算法
不同系统的调度算法批处理系统中的调度先来先服务最短作业优先最短剩余时间优先交互式系统中的调度轮转调度优先级调度多级队列最短进程优先保证调度彩票调度公平分享调度实时系统中的调度批处理系统中的调度先来先服务在所有调度算法中,最简单的是非抢占式的先来先服务(first-come first-severd)算法。使用该算法,进程按照它们请求CPU的顺序使用CPU。基本上,有一个就绪进程的单一队列。早上,当第一个作业从外部进入系统,就立即开始并允许运行它所期望的时间。不会中断该作业,因为它需要很长的时间运行。当
2021-08-29 16:19:46
708
原创 消息传递和屏蔽
消息传递和屏蔽消息传递消息传递系统的设计要点用消息传递解决生产者-消费者问题屏障消息传递消息传递系统的设计要点消息传递系统面临着许多信号量和管程所未涉及的问题和设计难点,特别是位于网络中不同机器上的通信进程的情况。例如,消息有可能被网络丢失。为了防止消息丢失,发送方和接收方可以达成如下一致:一旦接收到信息,接收方马上回送一条特殊的确认(acknowledgement)消息。如果发送方在一段时间间隔内未收到确认,则重发消息现在考虑消息本身被正确接收,而返回给发送者的确认信息丢失的情况。发送者将重发信息
2021-08-28 16:54:04
156
原创 深入理解互斥量
互斥量互斥量Pthread中的互斥互斥量如果不需要信号量的计数能力,有时可以使用信号量的一个简化版本,称为互斥量(mutex)。互斥量仅仅适用于管理共享资源或一小段代码。由于互斥量在实现时既容易又有效,这使得互斥量在实现用户空间线程包时非常有用互斥量是一个可以处于两态之一的变量:解锁和加锁。这样,只需要一个二进制位表示它,不过实际上,常常使用一个整型量,0表示解锁,而其他所有的值则表示加锁。互斥量使用两个过程。当一个线程 (或进程)需要访问临界区时,它调用mutex_lock。如果该互斥量当前是解锁的
2021-08-16 14:48:50
2977
转载 深入理解信号量
信号量信号量用信号量解决生产者-消费者问题信号量信号量是E.W.Dijkstra在1965年提出的一种方法,它使用一个整型变量来累计唤醒次数,供以后使用。 在他的建议中引入了一个新的变量类型,称作信号量(semaphore)。一个信号量的取值可以为0(表示没有保存下来的唤醒操作)或者为正值(表示有一个或多个唤醒操作)Dijkstra建议设立两种操作:down和up(分别为一般化后的sleep和wakeup)。对一信号量执行down操 作,则是检查其值是否大于0。若该值大于0,则将其值减1(即用掉一个保
2021-08-15 15:02:16
983
原创 实现互斥的几种方案
实现互斥的方案忙等待的互斥屏蔽中断锁变量严格轮换法Peterson解法TSL指令睡眠与唤醒生产者-消费者问题忙等待的互斥屏蔽中断在单处理器系统中,最简单的方法是使每个进程在刚刚进入临界区后立即屏蔽所有中断,并在就要离开之前再打开中断。屏蔽中断后,时钟中断也被屏蔽。CPU只有发生时钟中断或其他中断时才会进行进程切换,这样,在屏蔽中断之后CPU将不会被切换到其他进程。于是,一旦某个进程屏蔽中断之后,它就可以检查和修改共享内存,而不必担心其他进程介入这个方案并不好,因为把屏蔽中断的权力交给用户进程是不明智
2021-08-13 20:09:57
3337
原创 竞争条件和临界区
竞争条件和临界区竞争条件临界区竞争条件在一些操作系统中,协作的进程可能共享一些彼此都能读写的公用存储区。这个公用存储区可能在内存中(可能是在内核数据结构中),也可能是一个共享文件。这里共享存储区的位置并不影响通信的本质及其带来的问题。为了理解实际中进程间通信如何工作,我们考虑一个简单但很普遍的例子:一个假脱机打印程序。当一个进程需要打印一个文件时,它将文件名放在一个特殊的假脱机目录(spooler directory)下。另一个进程(打印机守护进程)则周期性地检查是否有文件需要打印,若有就打印并将该文件
2021-08-12 16:52:29
367
原创 弹出式线程
弹出式线程在分布式系统中经常使用线程。一个有意义的例子是如何处理到来的消息,例如服务请求。传统的方法是将进程或线程阻塞在一个receive系统调用上,等待消息到来。当消息到达时,该系统调用接收消息,并打开消息检查其内容,然后进行处理不过,也可能有另一种完全不同的处理方式,在该处理方式中,一个消息的到达导致系统创建一个处理 该消息的线程,这种线程称为弹出式线程如图所示:好处:由于这种线程相当新,没有历史——没有必须存储的寄存器、堆栈诸如此类的内容,每个线程从全新开始,每一个线程彼此之 间都完全一
2021-08-11 14:24:57
213
原创 调度程序激活机制
调度程序激活机制调度程序激活机制调度程序激活机制尽管内核级线程在一些关键点上优于用户级线程,但无可争议的是内核级线程的速度慢。因此,研究人 员一直在寻找在保持其优良特性的前提下改进其速度的方法。下面我们将介绍Anderson等人(1992)设计的这样一种方法,称为调度程序激活(scheduler activation)机制调度程序激活工作的目标是模拟内核线程的功能,但是为线程包提供通常在用户空间中才能实现的更好的性能和更大的灵活性。特别地,如果用户线程从事某种系统调用时是安全的,那就不应该进行专门的非
2021-08-11 14:15:16
472
原创 线程的实现
线程的实现POSIX线程在用户空间中实现线程在内核中实现线程混合实现POSIX线程为实现可移植的线程程序,IEEE在IEEE标准1003.1c中定义了线程的标准。它定义的线程包叫做 Pthread。大部分UNIX系统都支持该标准。这个标准定义了超过60个函数调用,如果在这里列举一遍就太多 了。取而代之的是,我们将仅仅描述一些主要的函数,以说明它是如何工作的。图中列举了这些函数调用在用户空间中实现线程有两种主要的方法实现线程包:在用户空间中和在内核中第一种方法是把整个线程包放在用户空间中,内核对线
2021-08-10 14:46:39
137
原创 深入了解I/O设备
I/O设备CPU和存储器不是操作系统惟一需要管理的资源。I/O设备也与操作系统有密切的相互影响I/O设备一般包括两个部分:设备控制器和设备本身。控制器是插在电路板上的一块芯片或一组芯片, 这块电路板物理地控制设备。它从操作系统接收命令,例如,从设备读数据,并且完成数据的处理在许多情形下,对这些设备的控制是非常复杂和具体的,所以,控制器的任务是为操作系统提供一个简 单的接口(不过还是很复杂的)。例如,磁盘控制器可以接受一个命令从磁盘2读出11206号扇区,然后,控 制器把这个线性扇区号转化为柱面、扇区和
2021-08-09 20:09:40
175
原创 深入了解存储器
存储器存储器的结构寄存器高速缓存缓存主存磁盘磁带存储器的结构在理想情形下,存储器应该极为迅速(快于执行一 条指令,这样CPU不会受到存储器的限制),充分大,并且非常便宜。但是目前的技术无法同时满足这三个 目标,于是出现了不同的处理方式。存储器系统采用一种分层次的结构寄存器存储器系统的顶层是CPU中的寄存器。它们用与CPU相同的材料制成,所以和CPU一样快。显然,访问它们是没有时延的。其典型的存储容量是,在32位CPU中为32×32位,而在64位CPU中为64×64位。在这两种情形下,其存储容量都小
2021-08-08 13:20:38
430
原创 处理器介绍
处理器计算机的“大脑”是CPU,它从内存中取出指令并执行之。在每个CPU基本周期中,首先从内存中取出指 令,解码以确定其类型和操作数,接着执行之,然后取指、解码并执行下一条指令。按照这一方式,程序被 执行完成每个CPU都有其一套可执行的专门指令集。所以,Pentium不能执行SPARC程序,而SPARC也不能执行 Pentium程序。由于用来访问内存以得到指令或数据的时间要比执行指令花费的时间长得多,因此,所有的 CPU内都有一些用来保存关键变量和临时数据的寄存器。这样,通常在指令集中提供一些指令,用以
2021-08-06 16:02:45
321
原创 经典线程模型
线程模型线程模型线程模型进程模型基于两种独立的概念:资源分组处理与执行。有时,将这两种概念分开会更有益,这也引入了“线程”这一概念。我们将先来看经典的线程模型:理解进程的一个角度是,用某种方法把相关的资源集中在一起。进程有存放程序正文和数据以及其他资 源的地址空间。这些资源中包括打开的文件、子进程、即将发生的报警、信号处理程序、账号信息等。把它 们都放到进程中可以更容易管理另一个概念是,进程拥有一个执行的线程,通常简写为线程(thread)。在线程中有一个程序计数器, 用来记录接着要执行哪一条指令。
2021-08-05 14:41:01
481
原创 为什么要有线程
线程产生的原因线程的优点线程的优点人们需要多线程的主要原因是,在许多应用中同时发生着多种活动。其 中某些活动随着时间的推移会被阻塞。通过将这些应用程序分解成可以准并行运行的多个顺序线程,程序设 计模型会变得更简单。有了多线程概念之后,我们 才加入了一种新的元素:并行实体共享同一个地址空间和所有可用数据的能力。对于某些应用而言,这种能 力是必需的,而这正是多进程模型(它们具有不同地址空间)所无法表达的由于线程比进程更轻量级,所以它们比进程更容易(即更快)创建, 也更容易撤销。在许多系统中,创建一个线
2021-08-03 22:17:09
1756
1
原创 深入理解进程
进程为什么会产生进程概念进程模型进程和程序间的区别创建进程进程的终止进程的层次结构进程的状态进程的实现为什么会产生进程概念所有现代的计算机经常会在同一时间做许多件事,在任何多道程序设计系统中,CPU由一个进程快速切换至另一个进程,使每个进程各运行几十或几百个 毫秒。严格地说,在某一个瞬间,CPU只能运行一个进程。但在1秒钟期间,它可能运行多个进程,这样就 产生并行的错觉。有时人们所说的伪并行就是指这种情形,以此来区分多处理器系统(该系统有两个或多个 CPU共享同一个物理内存)的真正硬件并行。人们很难对多
2021-08-02 16:53:15
166
转载 C++运算符重载
C++运算符重载重载的概念C++ 中的运算符重载可重载运算符/不可重载运算符一元运算符重载二元运算符重载关系运算符重载输入/输出运算符重载总结重载的概念C++ 允许在同一作用域中的某个函数和运算符指定多个定义,分别称为函数重载和运算符重载。重载声明是指一个与之前已经在该作用域内声明过的函数或方法具有相同名称的声明,但是它们的参数列表和定义(实现)不相同。当您调用一个重载函数或重载运算符时,编译器通过把您所使用的参数类型与定义中的参数类型进行比较,决定选用最合适的定义。选择最合适的重载函数或重载运算符
2021-08-01 22:19:12
92
原创 C++多态的实现原理
C++多态的实现原理虚函数和多态多态的表现形式多态的作用多态的一个例子构造函数和析构函数中存在多态吗?多态的实现原理虚函数表虚析构函数纯虚函数和抽象类虚函数和多态虚函数:在类的定义中,前面有 virtual 关键字的成员函数称为虚函数virtual 关键字只用在类定义里的函数声明中,写函数体时不用比如:class Base { virtual int Fun() ; // 虚函数};int Base::Fun() // virtual 字段不用在函数体时定义{ }多态的
2021-07-31 21:23:12
815
2
原创 虚继承场景下的C++对象模型
C++对象模型菱形继承虚继承的对象模型菱形继承我们先来回忆一下C++中的菱形继承菱形继承的概念:两个派生类继承同一个基类又有某个类同时继承两个派生类这种继承被称为菱形继承,或钻石继承菱形继承的问题:羊继承了动物的数据,驼同样继承了动物的数据,当草泥马使用数据时,就会产生二义性草泥马继承自动物的数据继承了两份,其实我们只需要一份就可以了解决方法:当菱形继承,两个父类拥有相同的数据,需要加以作用域区分利用虚继承,解决菱形继承的问题虚继承的对象模型普通继承是子类拷贝并修改
2021-07-30 15:58:36
125
原创 普通继承环境下的C++对象模型
C++对象模型对象模型基础普通继承场景下的对象模型对象模型基础C++在C的基础上引入了面向对象的程序设计思想,类的封装、继承和多态使得C++功能更加强大,C++的类包含数据成员和成员函数:数据成员: 静态数据成员,非静态数据成员成员函数: 非静态成员函数、静态函数、虚函数C++对象模型研究C++类的数据成员和成员函数在内存中如何布局的问题:例如:class Base{public: int member; // 非静态数据成员 static int smember; /
2021-07-29 21:31:59
123
原创 使用BIOS进行键盘输入
使用BIOS进行键盘输入int 9中断例程对键盘输入的处理使用int 16h中断例程读取键盘缓冲区大多数有用的程序都需要处理用户的输入,键盘输入是最基本的输入,程序和数据需要长期存储,BIOS为这种外设的I/O提供了最基本的中断例程int 9中断例程对键盘输入的处理键盘输入将引发9号中断,BIOS提供了int 9中断例程,CPU在9号中断发生后,执行int 9中断例程,从60h端口读出扫描码,并将其转化为相应的ASCII码或状态信息,存储在内存的指定空间(键盘缓冲区或状态字节)中下面,我们通过下面几
2021-07-28 20:48:56
770
原创 直接定址表
直接定址表描述单元长度的标号在其他段中使用数据标号直接定址表描述单元长度的标号之前,我们一直在代码段中使用标号来标记指令,数据,段的起始地址,比如:assume cs:codecode segment a:db 1,2,3,4,5,6,7,8 b:dw 0start: mov si,offset a mov bx,offset b程序中,code,a,b,start都是标号,这些标号仅仅表示了内存单元的地址但是,我们还可以使用一种标号,这种标号不但表示内存单元的地址,还表示了内存
2021-07-27 20:55:37
211
原创 汇编外中断
外中断接口芯片和端口外中断信息PC机键盘的处理过程CPU在计算机系统中,除了能够执行指令,进行运算之外,还应该能够对外部设备进行控制,接收它们的输入,向它们进行输出要及时处理外设的输入,显然需要解决两个问题:外设的输入随时可能发生,CPU如何得知?CPU从何处得到外设的输入?接口芯片和端口PC系统的接口卡和主板上,装有各种接口芯片,这些外设接口芯片的内部有若干寄存器,CPU将这些寄存器当作端口来访问外设的输入不直接送入内存和CPU,而是送入相关的接口芯片的端口中,CPU向外设的输出也不是直
2021-07-26 23:45:16
111
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人