博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

第七次读书笔记

Posted on 2018-04-19 17:20  HelenL  阅读(191)  评论(2编辑  收藏  举报

《程序员的自我修养》

  从多道程序,到分时系统,再到多任务系统,操作系统的性能越来越强。多任务系统接管了所有的硬件,并且本身运行在一个受硬件保护的级别,所有应用程序都以进程的形式运行在比操作系统权限更低发级别,有独立的地址空间,并相互隔离,每个进程都有优先级,采用抢占式的CPU分配方式,操作系统可以强制剥夺CPU资源并分配给他认为目前最需要的进程。CPU在多进程之间进行快速切换,从而造成很多进程都在同时运行的假象。

  操作系统事实上是对硬件的管理和抽象。对于操作系统上面的运行库和应用程序来说,它们希望看到的是一个统一的硬件访问模式,对于我们来说,我们不想关心硬件的I/O到底是怎么操作的。处理硬件细节的是操作系统中的硬件驱动程序来完成的。而这些驱动程序通常由硬件制造商来完成。操作系统开发者为硬件生产厂商提供了一系列接口和框架。又是接口。接口很重要。

  以上提到隔离,其实是指每一个程序需要一个简单的执行环境,有单一的地址空间,仿佛自己占领了整个CPU,而不用去关心其他程序。而这里的地址空间,是指虚拟的地址空间,每个进程只能访问自己的虚拟空间,它会被映射成真是的虚拟空间。我想大概就和子函数类似,子函数内部的变量只能由自己访问,这就是进程的隔离。书上提到了分段的办法,这也是我们微机原理上学的办法,所以说我们之所以要进行分段,就是为了能够更方便的编程和进行进程的管理。后来这种技术改进成分页,也和磁盘构造是息息相关的。

  线程是轻量级的进程,是程序执行流的最小单元,一个标准线程由线程ID,当前指令指针(PC)、寄存器集合和堆栈组成。一个进程由一个到多个线程组成,各个线程之间共享程序的内存空间,多线程有利于计算机尽可能发挥工作性能。

  虽然说线程的访问是很自由的,依上所述,它可以访问进程内存里的所有数据,但线程也拥有私有储存空间,如栈,局部存储,寄存器。比如说在C语言中局部变量、函数参数就是线程私有的,而全局变量,堆上的数据,静态变量,程序代码,打开的文件,(A打开的文件可以被B线程读写)这些则是线程共享。

  在一个不断在处理器上切换不同的线程的行为称之为线程调度。在线程调度中,线程拥有三种状态:运行、就绪、等待。那么如何调度就成为了一门学问。调度方式一般遵循优先级调度和轮转法调度。在windows中和Linux中都有程序可以对线程进行优先级设置,系统也会自动调整。频繁等待的线程被称为IO密集型线程,很少等待的线程被称为密集型线程。IO密集型线程总比CPU密集型线程容易得到系统安排的优先级的提升。

  当线程用尽时间片吼会被强制剥夺继续执行的权利,而进入就绪状态,这个过程叫做抢占。

  在Linux中 有几个系统调用函数来创建一个新的任务:fork/exec/clone

  其中fork是复制当前进程的意思。并且其有一个重要特点,fork并不复制原任务的内存空间,而是和原任务共享一个写时复制的内存弓箭,也就是说两个人物可以同时自由读取内存,但任意一个任务试图对内存进行修改时,内存就会复制一份提供给修改方单独使用,以免影响到其他的任务使用。

  fork只能够产生本任务的镜像,因此需要使用exec配合才能够启动别的新任务。如果要产生新线程则要用clone。

  fork在Linux上的意义是否和git上的相同呢,似乎有点类似,都有复制的意思,其他就不太清楚了hhh。

  单指令的操作称为原子的,因为无论如何,单条指令的执行不会被打断。但是对于复杂的数据结构原子操作指令就显得力不从心。这时我们需要将各个线程对同一个数据的访问同步。是指在一个线程访问数据未结束的时候,其他线程不得对同一个数据进行访问。同步的方式时使用锁。

  但有时候使用锁也是没有用的,有时候编译器会过度优化,这时候无法保证多线程安全。

  事实上之前编大作业的时候也出现过这种问题。这时候我们可以使用volatile关键字试图阻止过度优化。volatile基本可以做到两件事情:1是阻止编译器为了提高速度将一个变量缓存到寄存器内而不回写。2是阻止编译器调整操作volatile变量的指令顺序。

  现在我们用的比如visual studio是集成开发环境(IDE),这样的IDE一般都将编译和链接的过程一步完成,把编译和链接合并到一起的过程称为构建。IDE和编译器提供的默认配置、编译和链接参数,这虽然方便,但是系统如那件的运行机制与机理被掩盖。而事实就是,当我们的程序出错的时候,我们通常不知道发生了什么。这也大概是这本书要带给我们的。

  一个简单程序运行分为四个步骤,分别是预处理、编译、汇编和链接。

  在linux中我们使用一系列gcc 命令来实现以上四个步骤中的一个或几个过程,例如说我们想要知道头文件的包含是否正确,我们就可以查看预处理后的文件。所以gcc这个命令只是这些后台程序的白装,它会根据不同的参数要求去调用程序。

  经过汇编之后,并不是输出一个可执行文件,而是生成目标文件,目标文件经过链接生成可执行文件。

  看了这些,虽然只看了一点,但有种我将不会只会对着CSDN上给出代码一行一行对着抄并不知所以的预感。虽然也不知道能够缓解多少这种情况。总之还是有所期待的。