同步的例子
Solaris
实现各种锁以支持多任务、多线程(包括实时线程)和多处理
在保护数据不受短代码段影响时,使用自适应互斥体以提高效率
当较长的代码段需要访问数据时,使用条件变量和读写器锁定
使用旋转门对等待获取自适应互斥锁或读写锁的线程列表进行排序
Windows XP
使用中断掩码来保护对单处理器系统上的全局资源的访问
在多处理器系统上使用自旋锁
还提供了分派器对象,可以充当互斥体和信号量
Dispatcher对象也可以提供事件
事件的作用类似于条件变量
Linux
Linux:
在内核版本2.6之前,禁用中断来实现短的临界部分
版本2.6和更高版本,完全抢占
Linux提供了:
信号量
自旋锁
Pthreads
Pthreads API与操作系统无关
它提供了:
互斥锁
条件变量
不可移植的扩展包括:
读写锁
自旋锁
原子事务
原子模型
确保操作(指令的集合)作为单个逻辑工作单元发生,或作为整体发生,或根本不发生
涉及数据库系统领域
挑战是在计算机系统失败的情况下确保原子性
事务-执行单一逻辑功能的指令或操作的集合
这里我们关注的是稳定存储磁盘的变化
事务是一系列的读写操作
由提交(事务成功)或中止(事务失败)操作终止
必须回滚终止的事务,以撤消它所执行的任何更改
存储介质类型
易失性存储——存储在这里的信息在系统崩溃时无法存活
例如:主存,缓存
非易失性存储——信息通常在崩溃后仍然存在
例如:磁盘和磁带
稳定的存储-信息从不丢失
实际上不可能,所以通过复制或RAID来近似于具有独立故障模式的设备
目标是在失败导致易失性存储上的信息丢失时,确保事务原子性
基于日志恢复
将事务中所有修改的信息记录到稳定存储中
最常见的是写前日志记录
日志稳定存储,每个日志记录描述单个事务的写操作,包括
交易名称
数据项名称
旧值
新值
当事务Ti启动时,Ti启动写入日志的>
Ti提交在Ti提交时写入>
在对数据进行操作之前,日志条目必须达到稳定的存储
- 基于日志恢复算法
使用日志,系统可以处理任何易失性内存错误
Undo(Ti)恢复Ti更新的所有数据的值
Redo(Ti)设置事务Ti中所有数据的值为新值
Undo(Ti)和redo(Ti)必须是幂等的
多次执行必须与一次执行具有相同的结果
如果系统失败,通过日志恢复所有更新数据的状态
如果日志包含 without , undo(Ti)
如果日志包含 and , redo(Ti)
动态检查点
日志可能变得很长,恢复可能需要很长时间
检查点缩短了日志和恢复时间。
检查点方案:
将当前在volatile存储器中的所有日志记录输出到稳定存储器
将所有修改过的数据从易失存储器输出到稳定存储器
将日志记录输出到稳定存储上的日志
现在恢复只包括Ti,这样Ti在最近的检查点之前开始执行,在Ti之后开始执行所有事务
所有其他事务已经在稳定存储上
并发事务
必须等同于串行执行-串行性
能否在临界区执行所有事务
效率低下,限制太多
并发控制算法提供了可序列化性
可序列化
考虑两个数据项A和B
考虑事务T0和T1
自动执行T0、T1
执行顺序称为schedule
被称为串行调度的原子执行的事务顺序
对于N笔交易,有N笔!有效的序列计划
时间表1: T0到T1
非序列计划
Nonserial schedule allows overlapped execute
结果执行不一定不正确
考虑时间表S、operations Oi , Oj of Transactions Ti and Tj,
如果使用至少一次写入来访问相同的数据项,则会发生冲突
如果Oi、Oj是连续的,并且不同交易的操作& Oi和Oj不冲突
那么S '与交换订单Oj Oi等同于S
非序列计划
我们说,如果可以通过一系列非冲突操作的交换,将一个序列转换成一个序列,那么这个序列就是冲突可串行化的。
锁协议
确保可串行化的一种方法是将锁与每个数据项相关联,并且每个事务遵循用于访问控制的锁定协议。
共享锁–T在itemQ上有共享模式锁,T可以读取Q,但不能写入Q
独占锁-T有独占模式锁定,T可以读写Q
要求itemQ上的每个交易获得适当的锁
如果锁已经持有,新的请求可能需要等待
类似于读者-作者算法
两阶段锁定协议
两阶段锁定协议确保了冲突的可串行化
每个事务分两个阶段发出锁定和解锁请求
增长—事务可以获得锁,但不能释放任何锁
收缩—事务可能会释放锁,但不会获得任何新锁。
最初,交易是成长阶段。事务根据需要获取锁。一旦事务释放了锁,它就进入了收缩阶段,并且不能再发出锁请求
不防止死锁
基于时间戳的协议
提前在交易中选择订单–时间标记
与时间戳相关联的事务层
TS(Ti) < TS(Tj)如果Ti在Tj之前进入系统
终端服务可以由系统时钟产生,也可以在每次交易时逻辑计数器递增
时间戳决定了可串行化顺序
如果TS(Ti) < TS(Tj),系统必须确保生产计划与Ti出现在Tj之前的系列计划相同
基于时间戳的协议实现
数据项Q有两个时间戳
W-timestamp(Q) – largest timestamp of any transaction that executed write(Q) successfully
R-timestamp(Q) – largest timestamp of successful read(Q)
每当执行读取(Q)或写入(Q)时更新
时间戳排序协议确保执行任何冲突的读写操作
按时间戳顺序
时间戳排序协议
假设执行写操作问题
如果TS(Ti) < R-timestamp(Q),则之前需要由Ti产生的Q值,并且Ti认为它永远不会产生
操作被拒绝,回滚
如果TS(Ti)< W-时间戳(Q),Ti试图写入Q的值
行动遭到拒绝,撤回
否则,执行写操作
作为读或写操作的结果,事务级被回滚,并被分配一个新的时间戳,然后被重新启动