Linux内核31-Seqlock

简介: Linux内核31-Seqlock

1 什么是seqlock锁?


上一篇文章中,我们已经学习了读/写自旋锁的工作原理和实现方式(基于ARM架构体系)。但是,有一个问题我们不得不考虑,那就是read锁和write锁的优先级问题:它们具有相同的优先级,所以,读操作必须等到写操作完成后才能执行,同样,写操作必须等到读操作完成后才能执行。

Linux2.6内核版本引入了Seqlock锁,与读写自旋锁基本一样,只是对于写操作来说,具有更高的优先级;也就是说,即使现在读操作正在执行,写操作也会被立即执行。这个策略的优点就是,写操作绝不会等待(除非是有其它写操作在占用锁);缺点就是,读操作可能需要读取多次,才能获取正确的备份。


2 seqlock锁实现


seqlock锁的数据结构如下所示,包含两个数据成员lockseqcount。查看代码可知,seqlock锁就是一个自旋锁加上一个序列计数器。

typedef struct {
    struct seqcount seqcount;       // 序列计数器
    spinlock_t lock;
} seqlock_t;

seqlock锁的工作原理是,对于读操作而言,每次读取数据前后,都要读取序列计数器2次,检查这前后两次的值是否一致,一致则认为可以使用锁。相反,如果一个新的写操作开始工作,增加序列计数器的值,隐含地告知读操作刚刚读到的数据不合法,需要重新读取数据。

seqlock_t类型变量初始化的方法有两种:一种是直接赋值SEQLOCK_UNLOCKED,另外一种是调用seqlock_init宏。写操作分别申请锁和释放锁,分别调用write_seqlock()write_sequnlock()。申请锁的过程是,申请seqlock_t数据结构中的自旋锁,并对序列计数器进行加一操作。释放锁的过程是,再一次对序列计数器进行加一操作,并释放掉自旋锁。这样操作的结果就是,写操作过程中,计数器的计数是奇数;没有写操作的时候,计数器是偶数。


3 seqlock锁使用范例


对于读操作来说,大概的代码实现如下所示:

unsigned int seq;
    do {
        seq = read_seqbegin(&seqlock);
        /* ... 临界代码段 ... */
    } while (read_seqretry(&seqlock, seq));

read_seqbegin()获取锁的当前序列号。read_seqretry()判断序列号是否一致,如果seq的值是奇数,则会返回1,也就是条件为真(也就是说,read_seqbegin()函数被调用之后,有写操作更新了数据)。因此,需要重新读取数据。如果seq的值是偶数,则读取数据成功。

值得注意的是,当读操作进入临界代码段时,无需禁止内核抢占。因为,我们允许写操作打断读操作的执行,这也是Seqlock锁写操作优先级高的设计初衷。但是,写操作进入临界代码段时,会自动禁止内核抢占。


4 seqlock锁使用场合


并不是所有的数据结构都能使用seqlock锁保护。因为seqlock锁有自身的缺点:因为写操作的优先级高于读操作,所以,对于写操作负荷比较的重的场合来说就不合适。如果写操作过于频繁,那么对读操作来说极为不公平,可能需要多次读取数据才能成功。所以,使用seqlock锁的场合应该满足下面的条件:

  • 要保护的数据结构不能包含指针,而且这些指针写操作修改,读操作进行引用。因为可能写操作修改了指针,而读操作还会引用之前的指针。
  • 要保护的数据结构必须是特别短小的代码,而且读操作比较频繁,写操作很少且非常快。(这也是读写自旋锁的使用原则)
  • 读操作的临界代码段中的代码不能有副作用(否则,多次读操作可能与单次读取有不同的效果)。

典型应用可以参考linux内核关于系统时间处理的部分。等分析Linux内核关于系统时间的部分时,再详细阐述。


相关文章
|
2月前
|
监控 Linux 开发者
理解Linux操作系统内核中物理设备驱动(phy driver)的功能。
综合来看,物理设备驱动在Linux系统中的作用是至关重要的,它通过与硬件设备的紧密配合,为上层应用提供稳定可靠的通信基础设施。开发一款优秀的物理设备驱动需要开发者具备深厚的硬件知识、熟练的编程技能以及对Linux内核架构的深入理解,以确保驱动程序能在不同的硬件平台和网络条件下都能提供最优的性能。
101 0
|
5月前
|
并行计算 Linux
Linux内核中的线程和进程实现详解
了解进程和线程如何工作,可以帮助我们更好地编写程序,充分利用多核CPU,实现并行计算,提高系统的响应速度和计算效能。记住,适当平衡进程和线程的使用,既要拥有独立空间的'兄弟',也需要在'家庭'中分享和并行的成员。对于这个世界,现在,你应该有一个全新的认识。
224 67
|
3月前
|
存储 负载均衡 算法
Linux2.6内核进程调度队列
本篇文章是Linux进程系列中的最后一篇文章,本来是想放在上一篇文章的结尾的,但是想了想还是单独写一篇文章吧,虽然说这部分内容是比较难的,所有一般来说是简单的提及带过的,但是为了让大家对进程有更深的理解与认识,还是看了一些别人的文章,然后学习了学习,然后对此做了总结,尽可能详细的介绍明白。最后推荐一篇文章Linux的进程优先级 NI 和 PR - 简书。
90 0
|
5月前
|
存储 Linux
Linux内核中的current机制解析
总的来说,current机制是Linux内核中进程管理的基础,它通过获取当前进程的task_struct结构的地址,可以方便地获取和修改进程的信息。这个机制在内核中的使用非常广泛,对于理解Linux内核的工作原理有着重要的意义。
199 11
|
6月前
|
自然语言处理 监控 Linux
Linux 内核源码分析---proc 文件系统
`proc`文件系统是Linux内核中一个灵活而强大的工具,提供了一个与内核数据结构交互的接口。通过本文的分析,我们深入探讨了 `proc`文件系统的实现原理,包括其初始化、文件的创建与操作、动态内容生成等方面。通过对这些内容的理解,开发者可以更好地利用 `proc`文件系统来监控和调试内核,同时也为系统管理提供了便利的工具。
239 16
|
8月前
|
Ubuntu Linux 开发者
Ubuntu20.04搭建嵌入式linux网络加载内核、设备树和根文件系统
使用上述U-Boot命令配置并启动嵌入式设备。如果配置正确,设备将通过TFTP加载内核和设备树,并通过NFS挂载根文件系统。
424 15
|
8月前
|
安全 Linux 测试技术
Intel Linux 内核测试套件-LKVS介绍 | 龙蜥大讲堂104期
《Intel Linux内核测试套件-LKVS介绍》(龙蜥大讲堂104期)主要介绍了LKVS的定义、使用方法、测试范围、典型案例及其优势。LKVS是轻量级、低耦合且高代码覆盖率的测试工具,涵盖20多个硬件和内核属性,已开源并集成到多个社区CICD系统中。课程详细讲解了如何使用LKVS进行CPU、电源管理和安全特性(如TDX、CET)的测试,并展示了其在实际应用中的价值。
189 4
|
10月前
|
负载均衡 算法 Linux
深入探索Linux内核调度器:公平与效率的平衡####
本文通过剖析Linux内核调度器的工作机制,揭示了其在多任务处理环境中如何实现时间片轮转、优先级调整及完全公平调度算法(CFS),以达到既公平又高效地分配CPU资源的目标。通过对比FIFO和RR等传统调度策略,本文展示了Linux调度器如何在复杂的计算场景下优化性能,为系统设计师和开发者提供了宝贵的设计思路。 ####
187 26
|
10月前
|
缓存 并行计算 Linux
深入解析Linux操作系统的内核优化策略
本文旨在探讨Linux操作系统内核的优化策略,包括内核参数调整、内存管理、CPU调度以及文件系统性能提升等方面。通过对这些关键领域的分析,我们可以理解如何有效地提高Linux系统的性能和稳定性,从而为用户提供更加流畅和高效的计算体验。
368 24
|
9月前
|
算法 Linux
深入探索Linux内核的内存管理机制
本文旨在为读者提供对Linux操作系统内核中内存管理机制的深入理解。通过探讨Linux内核如何高效地分配、回收和优化内存资源,我们揭示了这一复杂系统背后的原理及其对系统性能的影响。不同于常规的摘要,本文将直接进入主题,不包含背景信息或研究目的等标准部分,而是专注于技术细节和实际操作。