一身转战三千里,一剑曾百万师。这篇文章主要讲述读书分享《树莓派开始,玩转Linux》读书分享相关的知识,希望能为你提供帮助。
? ? 感谢杭州地铁六号线,这里有我大把的美好读书时间。
? ? 这次要分享的书是《树莓派开始,玩转Linux》。
书简介? ? 先上封面:
文章图片
? ? 树莓派是我三年前刚接触硬件入手的一个板子,那时还是raspberry pi 3B+,当时还搭配了扩展板和小车模块,现在的raspberry pi已经有4B了。读书分享从树莓派相关的开始也算是种默契,上个图(现在已经被我大卸好几块了):
文章图片
? ?本书简介:?
? ? 作者:Vamei(张腾飞)、周昕梓。
? ? 本书以树莓派为应用和切入点,循序渐进,核心在于讲解Linux操作系统。树莓派于2012年发布,因价廉、小巧、功能强大,一经发布就深受学生、开发者和极客的热捧。树莓派的操作系统是Linux,Linux最美的地方就是开放 ,Linux的开放是多层的:软件层面的开放,让用户可以免费使用;文档的开放,让你可以在终端可以方便地用man命令查询;操作系统的开放,让你可以自由调整系统也可以深入其原理;代码上的开放,让你可以随时看到世界上顶级程序猿的源代码 – 在Linux系统下,“实现”和“如何实现”是合二为一的。树莓派更棒的是,底层硬件也很开放,它可以方便地通过有线/无线/蓝牙的方式和硬件外设进行连接。
书中故事? ? 这部分是读起来最有味道的地方哈哈。
?故事一 埃本.厄普顿(Eben Upton)创造树莓派的故事?
? ? 2006年,剑桥大学新入学的本科生带着聪明的脑瓜、傲人的考试成绩进入计算机系,但是年轻的助教埃本.厄普顿却在发愁,原因是新生们的计算机水平实在太差。厄普顿明白,高手的养成有赖于青少年时期的动手实践,曾经玩计算机的都是一群极客,从小玩着UNIX系统和编译器长大。厄普顿自己就是个很好的例子,他生长于20世纪80年代,那个年代的英国人充满了动手精神。英国男人们以改装汽车和修冰箱为乐,厄普顿的父亲虽然是一位语言教授,却也喜欢在业余时间带着自己的儿子们把引擎大卸好几块,或者用继电器拼装起奇形怪状的家电,相同的手工精神也弥漫于计算机领域。那时市面上出现了很多为青少年设计的电脑,如Commodore 64(售价595美元)和BBC Micro(200~300英镑)。价格还算便宜,让学校和普通家庭也可以负担。由于母亲是学校老师,厄普顿本来可以免费使用学校的机房,但小伙伴们都有了自己的BBC Micro,聚一起就大聊各自的使用经验,不甘落后的厄普顿也存够了200英镑,给自己添置了一台BBC Micro,如图。BBC Micro非常尊重孩子们的使用电脑的自由,它不仅自带了编译环境,而且开放了大多数的设备接口。有一次,厄普顿想给自己的电脑增加一个鼠标,那时的鼠标可是“黑科技”,但是需要自己写驱动。厄普顿用轮询的方式给自己的鼠标写了一个简单的驱动,当这个驱动运行时,这台简陋的BBC Micro就会变得异常缓慢,但总归可以看到鼠标的移动了。
文章图片
? ? 相比于少年时的厄普顿,剑桥新生的条件好多了,接触的电脑配备了windows系统,各种图形化界面和软件,功能比BBC Micro强多了,但动手精神似乎消失了。少年时的情怀再次萌动,厄普顿计划再造一台BBC Micro,让新青少年可以尽情探索。但现实残酷,厄普顿刚开始设计的手工电脑性能太差、成本太高、且得不到剑桥的重视,就在厄普顿想要放弃时,麻省理工传出消息,想要以Apple-||为蓝本,制作一款廉价的简易电脑。“我们可不能输”,名校的竞争精神复活了厄普顿的项目。一个以厄普顿为首的开发小组形成,他们用电子邮件交流,为了方便指代设计的简易电脑,一封邮件中使用了“树莓”这种水果的名字。树莓从此成为了项目代称,由于原型机上只支持python编程语言,“树莓”后面又跟上了代表“Python”的“派”。树莓派(Raspberry Pi)就这样诞生了。
文章图片
? ? 2011年,BBC采访人员罗伊的一篇博客文章,让“树莓派”进入公众视野。但当时,树莓派离正式产品还有很远的距离,成本是最大的挑战。厄普顿的销售定价是15英镑。受博通公司(Broadcom)为手机生产的ARM处理器启动,决定采用ARM架构,解决了最关键的成本问题,即便如此,总成本还是难以控制在15英镑以下。为了能降低以太网接口的成本,他拜访了从原厂到代理到经销商的每一个环节,最终从一家欧洲经销商处获得了半价折扣;为了寻找合适的代工厂,他几乎走遍欧美和东亚,向经理们描述着自己的教育梦,冲着厄普顿的热忱,中国台湾的一家电路板厂商才以近乎赔钱的价格接下了最初的树莓派订单。2012年2月,树莓派终于解决了最后一个关键问题:把Linux操作系统导入到充当文件系统的SD卡上,这个信用卡大小的电脑,与这个星球上最流行的开源操作系统合体了。至此,最初的树莓派诞生了。
文章图片
?故事二 ARM与Intel的斗争?
? ? 树莓派的心脏 – ARM处理器的诞生,与BBC Micro这款启发了树莓派的电脑有关。1980年,“计算机”概念在欧美大热,大洋彼岸的苹果公司的Apple-||在20世纪70年代末创造了销售神话。个人电脑在美国风靡,温吞的英国人的节奏却慢了一拍,美国舶来的个人电脑都价格不菲,英国人不愿用一年的茶钱来换一台用途不明的机器。BBC是英国传媒业的龙头,当时公开招标一款廉价的微型计算机,中标的是艾康电脑公司(Acorn Computer Company),主要原因是他们正好有一台符合BBC预期的原型机,于是这款原型机被重命名为BBC Micro,成为电视节目的指定用机,并成为了当时英国最流行的个人电脑。但BBC Micro相比市面上其他个人电脑性能没有优势,艾康公司想把强大的Inter处理器用在BBC Micro上。当时的Intel正风光无两,借着IBM的大卖,Intel处理器几乎占据了整个个人电脑市场。当时的Intel对艾康这种小客户提不起兴趣,不愿给出太大的折扣,导致艾康最终放弃了Intel处理器,转而自行研发处理器。1985年,艾康公司给BBC Micro换上了ARM处理器,如图。
文章图片
? ? ARM是“Acorn RISC Machine”的简称,名字中的“RISC”(精简指令集),指的是ARM处理器对精简指令集的支持。这四个干巴巴的字母,却是对Intel最直接的叫板。原因很简单,Intel采用完全相反的“CISC”(复杂指令集),从直觉上来看,CISC处理器像是一辆超级跑车,让人趋之若鹜。RISC支持的指令虽然基础,但总可以通过基础指令的组合来实现CISC处理器的功能。RISC的汇编更占空间,编译也更耗时,但其结构简单,制造成本低,也比较省电。凭着ARM处理器,艾康守住了教育电脑市场,BBC Micro销量达到上百万台,直到1994年才彻底停产,但在更广阔的个人电脑市场,Intel的CISC处理器才是赢家,毕竟一台个人电脑往往会使用5到7年,为了应对漫长的使用期,用户当然希望自己手里的是一辆超级跑车。
? ? 1990年,艾康和苹果联合成立了ARM公司,苹果将ARM处理器用于牛顿掌上电脑(Apple Newton),这款产品直接启发了“商务通”等PDA(Person Digital Assistant)产品,甚至影响了iPhone的设计。掌上电脑需要节约使用电池,低功耗的ARM处理器正合适,但“牛顿”是一款早熟的产品,因此没能获得商业上的成功。这种绝望的状况下,ARM干脆彻底放弃了处理器的生产和销售。ARM当然不是自暴自弃,它通过卖设计收取一定的费用,把相关设计分享给有能力生产和销售的合作伙伴。合作伙伴生产出的每件ARM处理器,都要付给ARM公司一定的授权费,通过这种授权知识产权模式,让ARM公司可以专注于上游的设计,这让ARM公司可以快速地迭代开发。ARM开放的合作框架,掀起了一场反抗Intel的暴动。很多电子元件厂商都忌惮Intel的强势,与ARM公司合作,成了“蜀汉 联合,共抗曹魏”。就在ARM攒足粮草的关键时机,苹果终于发来助攻。乔布斯回归苹果,发布了革命性的iPhone,由于iPhone选用了ARM处理器,因此ARM的市场份额开始狂飙。事实上,Intel曾有机会拿下iPhone,在iPhone诞生之前,苹果就和Intel达成战略合作关系,但Intel内部并不看好iPhone,担心收不回投资成本。ARM的开放又一次战胜了Intel的封闭。随后,谷歌推出了安卓操作系统,刺激了一大波安卓手机厂商,寻求快速迭代的安装厂商们很自然地选用开放的ARM处理器。
?故事三 Linux操作系统的诞生?
? ? 树莓派的大脑 – Linux操作系统(Raspian,树莓派系统的安装可参考我的博客。Linux操作系统是。林纳斯.托瓦兹(Linus Torvalds)在1991年创造出来的。1991年的托瓦兹还是一名普通的大学生,刚刚买了一台3500美元的电脑,这对于任何一个芬兰家庭都是奢侈品,托瓦兹想尽办法付了电脑三分之二的钱,剩下的分期三年。托瓦兹后面沉浸在上面,妹妹萨拉意见很大经常会把隔壁咆哮,逼着正在拨号上网的哥哥让出电话线。考入赫尔辛基大学时,托瓦兹已经有了丰富的编程经验。他准备让自己的操作系统超越UNIX,UNIX是一个操作系统程序,比Windows年长了20岁。贝尔实验室的肯.汤普森(Ken Thompson)想在一台PDP-11型号的电脑上玩一款叫作《太空旅行》的游戏,就和同事丹尼斯.里奇(Dennis Ritchie)一起编写了UNIX操作系统,如图。
文章图片
? ? 拥有贝尔实验室的AT& T(美国电信电报公司) 当时有政府禁令,不能涉足软件业务,因此AT& T只允许教育机构使用UNIX,UNIX在大学里传播的很快。肯.汤普森的母校伯克利大学推出了一个更加好用的BBD(Berkeley Software Distribution)版本,因为这些计算机系的大学生用惯了UNIX,步入社会之后,也把UNIX推广到了IT公司,并衍生出各种商用版本。赫尔辛基大学也在刚刚购置的小型机上安装了UNIX,可供十多个学生同时在线使用,托瓦兹就是这台电脑的常客。后来托瓦兹把UNIX中的bash嫁接到自己的终端模拟程序上,很快又移植了C语言编译器GCC,由于UNIX下的大部分应用程序都是用C编写的,所以托瓦兹可以在自己的操作系统中编译几乎所有的UNIX应用程序。
? ? 1991年8月,托瓦兹在Minix新闻组上发帖:
? ? ?各位Minix用户,大家好。我正在制作一个(免费)的操作系统(只是作为爱好,不会像gnu那样专业)。这个项目从4月份就启动了,并将要准备好了。我想听听大家的意见,特别是大家喜欢或不喜欢Minix的地方,因为我的操作系统将会和Minix有些像。我正在移植bash和gcc。这意味着在接下来的几个月里,我将获得一些实质性的成果…此外,它没有用Minix的代码…?
? ? 那个时候,Minix是操作系统世界里的明星,Minix并不如UNIX成熟,但比起托瓦兹的操作系统还是强得多。Minix的作者是阿姆斯特丹自由大学的计算机系教授安德鲁.塔能鲍姆,他有言在先,不希望人们拓展他的源代码,也不会将其他用户的改进程序加入正式发行的Minix的版本里,这导致Minix的发展陷入停滞。相反,托瓦兹采用了GPL协议(General Public License),任何用户都可以使用和修改源代码,这充满了理想主义的味道,意味着托瓦兹不能从自己编写的程序获得直接的经济利益。当时圈内很多人都不看好Linux,UNIX之父汤普森和Minix之父塔能鲍姆曾公开批评Linux的实现方式。显然,他们低估了社区的重要性,即便托瓦兹不是最天才的程序员,但社区爱好者的贡献能让任何天才程序员都跟不上Linux的速度。1995年,用于HTTP服务的Apache服务器发布,催生了网站服务器的商业化,Linux大显神威。在网络服务器市场上,Linux彻底打败微软的Windows NT,成为大多数互联网公司的选择,网景、甲骨文、IBM等公司开始支持Linux系统,推动Linux开源运动,托瓦兹的照片因此登上了福布斯的封面,成为很多青少年的偶像。
? ? 来自芬兰的穷小子打败了一统天下的比尔.盖茨。
书中硬核 1、Linux进程的生命与进程间通信? ? 操作系统把计算机活动划分成进程,计算机开机时,Linux内核只创建了一个名为init的进程,除了init进程之外,Linux内核不直接创建其他新进程,都是通过fork机制创建的。所谓的fork,就是从父进程中复制出一个子进程。一个进程除了有一个PID之外,还会有一个PPID(Parent PID),用来存储父进程的PID,子进程可以通过查询自己的PPID来知道自己的父进程,从任何一个进程出发,循着PPID不断向上追溯,总会发现源头是init进程。因此Linux的所有进程也构成了一个树状结构,这个树状结构以init进程为根。进程总有终结的时候,进程可以自发终结,比如进程在main函数结尾调用return,或者在程序中的某个位置调用exit函数直接退出。此外,当进程出现如内存溢出等致命错误时,内核也会主动终结进程。
? ? 当某个进程终结时,父进程会获得通知,进程空间随即被清空,然而,进程附加信息会保留在内核中。按照Linux的惯例,父进程有义务对子进程使用wait系统调用,在调用wait之后,父进程暂停,等待子进程终结。子进程终结后,父进程能从内核中取出子进程的退出信息,并清空这个子进程的进程描述符,在完成了上述工作之后,父进程将恢复运行。若父进程早于子进程终结,子进程就会和进程树失联,成为一个孤儿进程(Orphand Process)。孤儿进程会过继给init进程,因此进程init是所有孤儿进程的父进程,而对孤儿进程调用wait的责任,也就转交给了init进程。当然,wait系统调用只是约定成俗的责任,Linux对此没有强制规定,一个程序也完全可以不对子进程调用wait,但这种程序会导致子进程的退出信息滞留在内核中,这时,子进程成为僵尸进程(Zombie Process)。当大量僵尸进程积累时,内核空间会被挤占,优秀的程序员应该杜绝这种情况的发生。
? ? 有了进程空间的概念,我们可以看到进程的独立性,每个进程的数据停留在自己的进程空间里,互不干涉。这样的独立性,让每个进程可以专注于自己的任务,大大减少了进程间相互干扰而出错的可能性。然而,有时我们又需要打破这种独立性,让进程之间分享数据,从而协调工作,这时就需要进行进程间通信(IPC, Inter-process Communication)。下面介绍几种IPC方式:
? ? (1) 一种原始的IPC方式就是进程间通过文件来交换信息,即一个进程往文件里写数据,另一个进程从文件中读取数据。这种方式需要用到存储器,相对于内存,这个方式效率很低,此外,多进程同时写入同一个文件,很容易造成文本混乱;
? ? (2) 信号也算是一种IPC,一个进程发出信号,放入目标进程的描述符,另一个进程进行系统调用时,在自己的描述符中看到该信号。两个进程通过信号进行了简单的数据交换,信号的一大缺点是无法大量交换数据;
? ? (3) 管道直接把一个进程的输出和另一个进程的输入连接起来,通过管道,进程间可以通过文本传输大量数据,由于管道兼具速度和数据量优势,因此在IPC方面,管道要比文件和信号都常用。管道在内核空间里会有一个专用的缓冲区,输出进程会向这个缓冲区不断地写入数据,而输入进程会从缓冲区按照顺序取出数据。管道的缓冲区不需要很大,被设计成环形的数据结构,可以循环利用;
? ? (4) 消息队列(Message Queue)与管道有些类似,不同的是消息队列的数据单元长度不定且消息队列两端允许多个进程参与。消息队列不依附于特定的进程,所以消息队列不会像管道那样自动消息,一旦创建,会一直留在内核空间中,直到某个进程删除该队列;
? ? (5) 共享内存的IPC方式打破了进程空间的独立性限制。一个进程可以将自己的内存空间中的一部分拿出来作为共享内存,并允许其他进程直接读写,在这个过程中,数据始终停留在同一个地方,不需要迁移到存储器空间或内核空间,所以它是效率最高的IPC方式,特别适合大数据量的情景,如图像处理;
? ? (6) 套接字也是一种常见的IPC方式,在互联网通信上扮演着关键角色。我们可以把互联网通信也理解成IPC问题,只不过这个时候的多个进程可以分布在不同电脑上。互联网上常用的网络协议都可以通过套接字的方式连接,从而连接分别位于两台计算机上的两个进程
2、Linux多进程的同步与调度? ? Linux系统是一个支持并发的操作系统,可以同时执行多个任务,多个进程通过IPC的数据沟通,可以合作完成一个复杂任务,然而,并发系统并不简单,必须解决同步的问题。在过去很长时间里,计算机使用的都是单核CPU,每个时刻单核的CPU只能执行一条指令。从指令的角度看,单核CPU计算机不能并发。但单核CPU计算机可以通过分时(Time-Sharing)来实现,所谓分时就是把时间分配给多个服务对象,实际还是串行。现代多核的CPU,从基础的物理层面实现了并发。当程序创建一个新的线程时,必须为这个线程建一个新的栈,每个栈对应一个线程。当某个栈执行到全部弹出时,对应线程完成任务,多个栈之间以一定的空白区域隔开,以备栈的增长。对于多线程来说,由于同一个进程空间中存在多个栈,任何一个空白区域被填满都会导致栈溢出崩溃。由于多线程共享了很多内存区域,它们可以直接读写堆上的内容,线程间的数据共享变得简单,因此多线程的数据交流成本要比多进程低得多。
? ? 在并发情况下,指令执行的先后顺序由内核决定,同一个线程内部,指令按照先后顺序执行,但不同线程之间的指令很难说清哪一个会先执行。这个时候,如果并发任务可以同时读取同一块数据,就会造成结果难以预测的情况。因此,在并发系统中,如果运行的结果依赖于不同线程执行的先后顺序,则会造成竞态条件。多线程的同步可以解决竞态条件问题。可以通过互斥锁(Mutex)、条件变量(Condition Variable)和读写锁(Reader-Writer Lock)来同步资源。
? ? (1) 互斥锁一般被设置成全局变量,它有锁上和打开两个状态。打开的互斥锁可以由某个线程获得,一旦获得,这个互斥锁会锁上,此后只有该线程有权打开,其他想要获得互斥锁的线程,要等到互斥锁再次打开的时候。可以将互斥锁想象成只能容纳一个人的洗手间,当有人进入洗手间时,将门锁上,其他人只能在互斥锁外面等待,等待的人并没有排队,谁先看到洗手间空了,就可以先冲进去;
? ? (2) 条件变量特别适用于多个线程共同等待某个条件发生的情况,如果不使用条件变量,那么每个线程就需要不断尝试获得互斥锁并检查条件是否发生,这样大大浪费了系统的资源;
? ? (3) 读写锁中包含了两把锁,即读锁?和写锁(W),应用程序用R锁来控制读取操作,如果一个线程获得R锁,读写锁允许其他线程继续获得。应用程序应该用R锁来控制读取操作。如果一个线程获得R锁,读写锁允许其他线程继续获得R锁,而不必等待该线程释放R锁。也就是说,多个进程可以同时读取同一资源。W锁用来控制写入操作,同一时间只能有一个线程获得W锁。不过,在获得W锁之前,线程必须等到所有持有共享读取锁的线程释放掉各自的R锁,以免自己的写入操作干扰到其他线程的读取;
? ? 内核中安排进程执行的模块称为调度器(Scheduler),最原始的调度策略是按照优先级排列好进程,等到一个进程运行完了再运行优先级较低的一个,但这种策略完全无法发挥多任务系统的优势。O(n) 调度器把时间分成大量的微小时间片(Epoch)。在每个时间片开始的时候,调度器会检查所有处在就绪状态的进程。调度器计算每个进程的优先级,然后选择优先级最高的进程来执行。一旦被调度器切换到执行,进程可以不被打扰地用尽这个时间片。如果进程没有用尽时间片,那么该时间片的剩余时间会增加到下一个时间片中。O(n)调度器在每次使用时间片前都要检查所有就绪进程的优先这个检查时间和进程中进程数目n成正比,这也正是该调度器复杂度为O(n)的原因。当计算机中有大量进程在运行时,这个调度器的性能将会被大大降低。为了解决O(n)调度器的性能问题,O(1) 调度器被发明了出来,并从 Linux2.6内核开始使用。顾名思义,O(1) 啁度器是指调度器每次选择要执行的进程的时间都是1个单位的常数,和系统中的进程数量无关。这样,就算系统中有大量的进程,调度器的性能也不会下降。O(1) 调度器的创新之处在于,它会把进程按照优先级排好,放入特定的数据结构中。在选择下一个要执行的进程时,调度器不用遍历进程就可以直接选择优先级最高的进程。
? ? 从2007年发布的 Linux2.6.23版本起,完全公平调度器(CFS, Completely Fair Scheduler) 取代了O(1) 调度器。CFS调度器不对进程进行任何形式的估计和猜测。这一点和O(1)区分互动和非互动进程的做法完全不同CFS调度器增加了一个虚拟运行时(Virtual runtime) 的概念。每次一个进程在CPU中被执行了一段时间,就会增加它虚拟运行时的记录。在每次选择要执行的进程时,不是选择优先级最高的进程,而是选择虚拟运行时最少的进程。完全公平调度器用一种叫红黑树的数据结构取代了O(1) 调度器的140个队列。红黑树可以高效地找到虚拟运行最小的进程。
3、Linux内存分页与分级存储【读书分享《树莓派开始,玩转Linux》读书分享】? ? 内存是计算机的主存储器。内存为进程开辟出进程空间,让进程在其中保存数据。内存用内存地址 (Memory Address) 来为每个字节的数据顺序编号。因此,内存地址说明了数据在内存中的位置,内存地址从0开始,每次増加1。这种线性增加的存储器地址称为线性地址 (Linear Address),用十六进制数来表示内存地址,地址空间的范围和地址总线 (Address Bus) 的位数直接有关,CPU通过地址总线来向内存说明想要存取数据的地址。内存的存储单元采用了随机读取存储器(RAM, Random Access Memory)。随机读取是指存储器的读取时间和数据所在位置无关。内存的一项主要任务就是存储进程的相关数据。之前已经看到过进程空间的程序段、全局数据、栈和堆,以及这些存储结构在进程运行中所起的关键作用。有趣的是,虽然进程和内存的关系如此紧密,但是进程并不能直接访问内存。在Linux下,进程不能直接读写内存中地址为0x位置的数据。进程中能访问的地址只能是虚拟内存地址 (Virtual Memory Address)。操作系统会把虚拟内存地址翻译成真实的内存地址,应用程序对物理内存地址一无所知,如图:
文章图片
? ? 虚拟内存地址和物理内存地址的分离,给进程带来便利性和安全性。但虚拟內存地址和物理内存地址的翻译,又会额外耗费计算机资源。如何能高效地翻译虚拟内存地址,记录对应关系最简单的办法,Linux采用了分页(Paging) 的方式来记录对应关系。所谓的分页,就是以更大尺寸的单位页(Page) 来管理内存。在 Linux中,通常每页大小为4KB。内存分页可以极大地减少所要记录的内存对应关系。我们已经看到,以字节为单位的对应记录实在太多了。如果把物理内存和进程空间的地址都分成页,内核只需要记录页的对应关系,相关的工作量就会大为减少。由于每页的大小是每个字节的4千倍,因此内存中的总页数只是总字节数的四千分之一。对应关系也缩减为原始策略的四千分之一。分页让虚拟内存地址的设计有了实现的可能无论是虚拟页,还是物理页,一页之内的地址都是连续的。这样一个虚拟页和一个物理页对应起来,页内的数据就可以按顺序一一对应。这意味着,虚拟内存地址和物理内存地址的末尾部分应该完全相同。大多数情况下,每一页有4096个字节。因为4096是2的12次方,所以地址最后12位的对应关系天然成立。把地址的这一部分称为偏移量(Offset)。偏移量实际上表达了该字节在页内的位置。地址的前一部分则是页编号。操作系统只需要记录页编号的对应关系。地址翻译过程如图:
文章图片
? ? 为了兼顾性能和成本,计算机大多采取分级存储的形式,从而让不同速度的存储元件协同工作。分级存储的设计,兼顾了读取速度、存储容量和计算机的稳定性。计算机把最快的存储元件用在最繁忙的地方,由于造价昂贵,CPU缓存的容量不大。当CPU需要读写某个内存地址时,它会先检查该内存地址的数据是否已经存在于某条缓存记录(Cache Entry) 中。如果缓存记录中的内存地址信息和CPU寻址信息相符,那就说明数据已经缓存了,这种情况叫作缓存命中(Cache Hit)。CPU会直接读写缓存中的目标记录,速度会比读写内存快很多。如果CPU想要读写的数据不在缓存中,就是缓存缺失 (Cache miss),那么缓存会增加一条新的缓存记录,把内存地址的数据加载到该缓存记录中。CPU随后从缓存中读写数据出于成本的原因。我们不可能把计算机的全部数据放在CPU缓存中。缓存中无法容纳的数据,只能存放于内存和SD卡这样速度较慢的存储空间中。既然这样,CPU缓存必须有一个策略,决定把哪些数据放在缓存中。为了应对缓存缺失的情况,缓存必须增加新的缓存记录。如果缓存已经没有空余的空间,则必须选择替换缓存中的一个记录。这条已经存在的缓存记录被称为牺牲者(Victim),新的缓存记录会被放在牺牲者所在的位置。
? ? 虚拟内存可以把一部分的外部存储器空间转换成内存空间,让应用程序可以虚拟地增加内存大小。这一技术的关键在于页交换(Page Swap)。所谓的页交换,就是进程空间和外部存储空间以页为单位交换数据。虚拟内存是一套管理数据和数据地址的方法,也可以用于外部存储空间的管理。操作系统可以把—部分外部存储空间划分成页,称为交换空间(Swap Space)。操作系统按照管理内存的方式来管理交换空间。物理内存和交换空间加在一起大大拓展了实际存储容量。当然,外部存储器读写速度慢的瓶颈始终存在。为了保证读写效率,应用程序只用在物理内存中的虚拟内存。当程序访问的数据恰好位于交换空间时,内核就会启动页交换,把交换空间的页转移到物理内存中,随后内核把分页对应到该物理内存位置,并通知应用程序继续进行数据操作。这样,程序访问的虚拟內存地址就指向了物理內存中的数据位置。对于应用程序来说,它只是根据虚拟内存地址进行操作,整个过程都不需要知道内核的幕后动作。
? ? 交换空间有交换分区和交换文件两种形式交换分区就是用一个独立的存储器分区作为交换空间和一般的磁盘分区不同,它没有文件系统,完全以页的方式进行管理交换文件是文件系统中的一个特殊文件,它占据的空间以页的方式进行管理,作为交换空间。可以通过/var/swapfile来修改交换内存。增加虚拟内存的教程可参考我的博客教程。CPU缓存技术可以弥补这种差异。如果内存中的部分空间可以用来缓存常用的文件系统数据,就可以大大减少外存的访问量。这种技术就是页缓存(Page Cache),页缓存和CPU缓存非常类似。在读取外存中的文件时,文件的数据会先存在内存中未使用的页上。此后,如果需要读取相同的数据,那么CPU可以直接从内存提取。当内存中可用于页缓存的空间填满时,计算机使用类似于LRU的策略选择牺牲者,用新的文件数据来替换掉缓存页。
? ? 缓冲的目的就是在内存中收集多个待写入的字符,再一次性写入外存。这一方面减少了进程切换状态的次数。另一方面,外存可以共用同一套准备动作,从而减少开销。内存为进程打开的文件保留缓冲区(Buffer),用于收集待写入文件的文本。缓冲区采用先进先出的策略,先写入的字符会被先取出。在刷新(Fush) 缓冲区时,缓冲区中存储的文本会按照先后次序一次性写入外存。操作系统的内核提供了缓冲区。因此,很多时候用write()系统写一个字符到文件,字符并没有真正存入文件。举个例子,进程往一个文件中写入15个字符"Vamei loves RPI",缓冲区的写入与刷新,如图:
文章图片
? ? Linux内核中内置了缓冲读写的功能。不过,鉴于缓冲是一种简单而有效的策略,应用程序也可以自己在进程空间中安排缓冲区,来把多次操作合并成一次操作。事实上,C标准库中的标准O函数,就负责在读写过程中管理进程空间的缓冲区。IPC和网络通信也经常用到相似的缓冲策略,以提高通信效率。
书中案例? ? “硬核” 模块很无聊吧,接下来的案例模块会非常有趣,不过这里不会详细赘述,因为后面我会抽业余时间动手实践,并挑选一些分享< 项目实践> 系列。
1、案例一 树莓派平板电脑? ? 连个触摸屏,兴趣不大哈哈。
2、案例二 天气助手? ? 使用树莓派读取互联网天气预报,并通过邮件定时发送给手机,这个项目还行,后面我会实践一下。
3、案例三 架设博客? ? 把博客假设在树莓派上,会涉及Typecho开源博客系统、使用花生壳搭建动态DNS服务等,这个项目在最近很火的野生钢铁侠稚辉君的分享中见过,后面我有空的话也会动手做一下。
4、案例四、五、六 离线下载、访客登记系统、节能照明系统? ? 没有兴趣哈哈。
5、案例七 树莓派挖矿? ? 虽然可能没啥输出,但是必须搞哈哈。
6、案例八、九 高性能计算、蓝牙即时通信? ? 硬件不到位,不搞。
7、案例十 开发一个Shell? ? 挺有意思的。
8、案例十 YOLO检测? ? 老本行了,有空再搞哈哈。
? ? ?扫描下方二维码即可关注我的微信公众号【极智视界】,获取更多实践项目资源和读书分享,让我们用极致+极客的心态来迎接AI !?
文章图片
推荐阅读
- [Linux用户空间编程-5](用IPTable实现NAT功能)
- [Linux用户空间编程-4](Linux虚拟网络设备TUN/TAP的工作原理与代码示例)
- Linux(shell)遍历目录删除指定文件,解决文件夹名称带空格问题
- Linux下软连接(link)和硬链接(hard)的区别
- RabbitMQ教程-在Linux上安装RabbitMQ报错解决方案
- Linux下parted命令使用 非交互式分区
- 在Linux下愉快工作的软件2022
- Flink on Yarn三部曲之二(部署和设置)
- Linux Kernel TCP/IP Stack — L7 Layer — Application Socket I/O 接口类型