无锁编程(六) - seqlock(顺序锁)
seqlock(顺序锁)
用于能够区分读与写的场合,并且是读操作很多、写操作很少,写操作的优先权大于读操作。 seqlock的实现思路是,用一个递增的整型数表示sequence。写操作进入临界区时,sequence++;退出临界区时,sequence再++。写操作还需要获得一个锁(比如mutex),这个锁仅用于写写互斥,以保证同一时间最多只有一个正在进行的写操作。 当sequence为奇数时,表示有写操作正在进行,这时读操作要进入临界区需要等待,直到sequence变为偶数。读操作进入临界区时,需要记录下当前sequence的值,等它退出临界区的时候用记录的sequence与当前sequence做比较,不相等则表示在读操作进入临界区期间发生了写操作,这时候读操作读到的东西是无效的,需要返回重试。 seqlock写写是必须要互斥的。但是seqlock的应用场景本身就是读多写少的情况,写冲突的概率是很低的。所以这里的写写互斥基本上不会有什么性能损失。 而读写操作是不需要互斥的。seqlock的应用场景是写操作优先于读操作,对于写操作来说,几乎是没有阻塞的(除非发生写写冲突这一小概率事件),只需要做sequence++这一附加动作。而读操作也不需要阻塞,只是当发现读写冲突时需要retry。 seqlock的一个典型应用是时钟的更新,系统中每1毫秒会有一个时钟中断,相应的中断处理程序会更新时钟(写操作)。而用户程序可以调用gettimeofday之类的系统调用来获取当前时间(读操作)。在这种情况下,使用seqlock可以避免过多的gettimeofday系统调用把中断处理程序给阻塞了(如果使用读写锁,而不用seqlock的话就会这样)。中断处理程序总是优先的,而如果gettimeofday系统调用与之冲突了,那用户程序多等等也无妨。 seqlock的实现非常简单: 写操作进入临界区时:
void write_seqlock(seqlock_t *sl)
{
spin_lock(&sl->lock); // 上写写互斥锁
++sl->sequence; // sequence++
}
写操作退出临界区时:
void write_sequnlock(seqlock_t *sl)
{
sl->sequence++; // sequence再++
spin_unlock(&sl->lock); // 释放写写互斥锁
}
读操作进入临界区时:
unsigned read_seqbegin(const seqlock_t *sl)
{
unsigned ret;
repeat:
ret = sl->sequence; // 读sequence值
if (unlikely(ret & 1)) { // 如果sequence为奇数自旋等待
goto repeat;
}
return ret;
}
读操作尝试退出临界区时:
int read_seqretry(const seqlock_t *sl, unsigned start)
{
return (sl->sequence != start); //看看sequence与进入临界区时是否发生过改变
}
而读操作一般会这样进行:
do {
seq = read_seqbegin(&seq_lock);// 进入临界区
do_something();
} while (read_seqretry(&seq_lock, seq)); // 尝试退出临界区,存在冲突则重试
版权声明:本文为博主原创文章,未经博主允许不得转载。
- 【专业技术】从4行代码看右值引用
- 【专业技术】8大你不得不知的Android调试工具
- 数据刷新中的并行改进(二) (r5笔记第76天)
- Spring【AOP模块】就这么简单
- 【专业技术】如何写出优美的C 代码?
- StringUtils工具类常用方法
- 数据刷新中的并行改进(三) (r5笔记第79天)
- SSH【史上最详细整合】
- Github 项目推荐 | TensorFlow 项目模板架构最佳实践
- 两个死锁的实例 (r5笔记第90天)
- SSM【史上最详细整合】
- 终结 finalize()和垃圾回收(garbage collection)
- 代码+实战:TensorFlow Estimator of Deep CTR —— DeepFM/NFM/AFM/FNN/PNN
- 【SSH测试整合Demo】企业人事管理系统
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- CentOS7.8下编译muduo库找不到Boost库报错的解决方法
- 使用 OWIN 搭建 OAuth2 服务器
- Hive on spark下insert overwrite partition慢的优化
- 系统学习Lambda表达式
- 一文搞懂 Flink Kafka Consumer 类两阶段提交
- 在 Nowin 下运行 ASP.NET 5 Beta 2
- Bytom侧链Vapor源码浅析-节点出块过程
- Kubernetes Pod OOM 排查日记
- Netty之旅:你想要的NIO知识点,这里都有!
- (数据科学学习手札92)利用query()与eval()优化pandas代码
- Spring Boot 集成 Elasticsearch 实战
- Python之错误和异常、模块(基础系列第四篇)
- Spark存储Parquet数据到Hive,对map、array、struct字段类型的处理
- 为什么这条异常没有上报? HTTP 429
- 三问Spring事务:解决什么问题?如何解决?存在什么问题?