当前位置 博文首页 > nameofcsdn的博客:操作系统
目录
1,计算机基本结构
2,设备驱动
3,进程和线程
4,线程调度
5,Linux系统的进程和线程
6,原子操作、同步、锁
7,可重入
8,过度优化 VS?线程安全
计算机可以分成CPU、内存、IO设备、其他部件。
总线(BUS)是用来连接所有部件的。
后来人们设计了高速设备处理的北桥芯片、低速设备处理的南桥芯片。
北桥PCI连接CPU、内存等,南桥ISA连接低速设备,
系统总线是PCI BUS,低速设备采用ISA总线汇总到南桥,高速设备有各自的总线汇总到北桥。
对于硬件设备,操作系统中的硬件驱动程序来实现具体操作,向上提供统一的访问模式,软件开发只需要调用接口。
设备驱动由设备厂商开发,操作系统开发者为设备厂商提供接口,按照该接口开发的驱动就可以在该操作系统上使用。
每个进程都有自己的独立内存空间。
线程,也可以成为轻量级进程,一个进程由一个到多个线程组成。
CPU的运行被切割成时间片,每个时间片运行一个线程,不断切换运行线程。
线程至少有3个状态:运行running、就绪ready、等待waiting
一个独立的不被其他操作影响的操作叫原子操作。
线程是共享数据的,为了避免同时读写导致数据异常,需要对数据进行访问同步,即一个线程访问的时候另外一个线程不能访问,这样的访问就是原子操作。
同步的最常见方法就是锁。
常见的锁:信号量、互斥量、临界区、读写锁、条件变量
函数重入
函数可重入指的是,该函数重入之后,不会产生任何不良后果。
可重入函数的特点:
(1)一些复杂的优化行为,会让锁失效。
案例一:将变量写入寄存器而不写回
编译器为了提高访问速度,将变量x写入寄存器而不写回,可能导致最终x的值是1,本来应该是2的。
案例二:交换指令顺序
编译器可能会为了提高效率而交换相邻两条无关指令的顺序,CPU的动态调度功能也会交换指令执行的顺序。
这样,最终结果可能就是r1=r2=0,本来是不可能这样的。
(2)使用volatile关键字,可以阻止编译器为了提高访问速度,将变量x写入寄存器而不写回,可以阻止编译器操作volatile变量的指令顺序。
所以,volatile可以解决案例一,但是无法解决案例二,因为CPU有动态调度。
(3)单例模式的double-check
案例三:还是交换指令顺序
这个是单例模式,申请一个对象,双重if判断是为了降低lock的调用,提高效率。
而(2)(3)的顺序是可以颠倒的,所以如果函数并发调用,就会有一个正在调用构造函数的对象的指针,被提供给调用方,从而引发错误。
CPU通常会提供一条屏障指令,用来组织指令交换顺序的时候穿过屏障,有的叫barrier,有的叫lwsync
例如,可以这样来解决上面的问题:
?
?
cs