首页 > 其他分享 >序列计数器和顺序锁 【ChatGPT】

序列计数器和顺序锁 【ChatGPT】

时间:2023-12-10 11:57:31浏览次数:44  
标签:seqcount 临界 计数器 序列 ChatGPT foo seqlock

序列计数器和顺序锁

介绍

序列计数器是一种具有无锁读取器(只读重试循环)和无写入者饥饿的读者-写者一致性机制。它们用于很少写入数据的情况(例如系统时间),其中读者希望获得一致的信息集,并且愿意在信息发生变化时重试。

当读取端临界区的序列计数在开始时是偶数,并且在临界区结束时再次读取相同的序列计数值时,数据集是一致的。数据集中的数据必须在读取端临界区内部被复制出来。如果在临界区开始和结束之间序列计数发生了变化,读者必须重试。

写者在其临界区的开始和结束时递增序列计数。在开始临界区后,序列计数是奇数,并指示读者正在进行更新。在写端临界区结束时,序列计数再次变为偶数,这样读者就可以取得进展。

序列计数器写端临界区绝不能被读端部分抢占或中断。否则,由于奇数序列计数值和被中断的写者,读者将会因为整个调度器滴答而旋转。如果该读者属于实时调度类,则它可能会永远旋转,内核将会活锁。

如果受保护的数据包含指针,则无法使用此机制,因为写者可能会使读者正在跟踪的指针失效。

序列计数器(seqcount_t)

这是原始计数机制,不保护多个写者。因此,写端临界区必须由外部锁进行串行化。

如果写串行化原语未隐式禁用抢占,则必须在进入写端部分之前显式禁用抢占。如果读取部分可以从硬中断或软中断上下文中调用,则必须在进入写部分之前分别禁用中断或底半部。

如果希望自动处理写者串行化和非可抢占性的序列计数要求,请改用顺序锁(seqlock_t)。

初始化:

/* 动态 */
seqcount_t foo_seqcount;
seqcount_init(&foo_seqcount);

/* 静态 */
static seqcount_t foo_seqcount = SEQCNT_ZERO(foo_seqcount);

/* C99 结构初始化 */
struct {
        .seq   = SEQCNT_ZERO(foo.seq),
} foo;

写路径:

/* 禁用抢占的串行化上下文 */

write_seqcount_begin(&foo_seqcount);

/* ... [[写端临界区]] ... */

write_seqcount_end(&foo_seqcount);

读路径:

do {
        seq = read_seqcount_begin(&foo_seqcount);

        /* ... [[读端临界区]] ... */

} while (read_seqcount_retry(&foo_seqcount, seq));

带关联锁的序列计数器(seqcount_LOCKNAME_t)

如序列计数器(seqcount_t)中所述,序列计数写端临界区必须进行串行化和非可抢占。此序列计数器的变体在初始化时将用于写者串行化的锁关联到序列计数器上,从而使lockdep能够验证写端临界区是否得到适当的串行化。

如果禁用了lockdep,则此锁关联是一个NOOP,既不会增加存储空间,也不会增加运行时开销。如果启用了lockdep,则锁指针将存储在结构seqcount中,并且lockdep的“锁已持有”断言将被注入到写端临界区的开始,以验证其是否得到适当的保护。

对于不隐式禁用抢占的锁类型,在写端函数中将强制执行抢占保护。

以下带关联锁的序列计数器已定义:

  • seqcount_spinlock_t
  • seqcount_raw_spinlock_t
  • seqcount_rwlock_t
  • seqcount_mutex_t
  • seqcount_ww_mutex_t

序列计数器的读取和写入API可以采用普通的seqcount_t或上述任何seqcount_LOCKNAME_t变体。

初始化(用支持的锁替换“LOCKNAME”):

/* 动态 */
seqcount_LOCKNAME_t foo_seqcount;
seqcount_LOCKNAME_init(&foo_seqcount, &lock);

/* 静态 */
static seqcount_LOCKNAME_t foo_seqcount =
        SEQCNT_LOCKNAME_ZERO(foo_seqcount, &lock);

/* C99 结构初始化 */
struct {
        .seq   = SEQCNT_LOCKNAME_ZERO(foo.seq, &lock),
} foo;

写路径:与序列计数器(seqcount_t)中的相同,同时从已获取关联写串行化锁的上下文中运行。

读路径:与序列计数器(seqcount_t)中的相同。

锁定序列计数器(seqcount_latch_t)

锁定序列计数器是一种多版本并发控制机制,其中嵌入的seqcount_t计数器的偶/奇值用于在受保护数据的两个副本之间进行切换。这使得序列计数器读取路径可以安全地中断自己的写端临界区。

当读端无法保护写端部分免受读者中断时,请使用seqcount_latch_t。这通常是在读端可以从NMI处理程序中调用时的情况。

有关更多信息,请查看raw_write_seqcount_latch()。

顺序锁(seqlock_t)

这包含了前面讨论的序列计数器(seqcount_t)机制,以及用于写者串行化和非可抢占性的嵌入式自旋锁。

如果读端部分可以从硬中断或软中断上下文中调用,请使用禁用中断或底半部的写端函数变体。

初始化:

/* 动态 */
seqlock_t foo_seqlock;
seqlock_init(&foo_seqlock);

/* 静态 */
static DEFINE_SEQLOCK(foo_seqlock);

/* C99 结构初始化 */
struct {
        .seql   = __SEQLOCK_UNLOCKED(foo.seql)
} foo;

写路径:

write_seqlock(&foo_seqlock);

/* ... [[写端临界区]] ... */

write_sequnlock(&foo_seqlock);

读路径,分为三类:

  1. 普通序列读取器永远不会阻塞写者,但如果检测到序列号的变化,它们必须重试,因为写者正在进行中。写者不会等待序列读取器:
    do {
            seq = read_seqbegin(&foo_seqlock);

            /* ... [[读端临界区]] ... */

    } while (read_seqretry(&foo_seqlock, seq));
  1. 锁定读取器会在写者或另一个锁定读取器进行中时等待。进行中的锁定读取器还会阻止写者进入其临界区。此读锁是独占的。与rwlock_t不同,只有一个锁定读取器可以获取它:
    read_seqlock_excl(&foo_seqlock);

    /* ... [[读端临界区]] ... */

    read_sequnlock_excl(&foo_seqlock);
  1. 根据传递的标记,条件无锁读取器(如1)或锁定读取器(如2)。这用于避免在写活动急剧增加时无锁读取器饥饿(太多重试循环)。首先尝试无锁读取(传递偶数标记)。如果该尝试失败(返回奇数序列计数,用作下一次迭代标记),则无锁读取将转换为完全锁定读取,不需要重试循环:
    /* 标记;偶数初始化 */
    int seq = 0;
    do {
            read_seqbegin_or_lock(&foo_seqlock, &seq);

            /* ... [[读端临界区]] ... */

    } while (need_seqretry(&foo_seqlock, seq));
    done_seqretry(&foo_seqlock, seq);

API 文档

https://www.kernel.org/doc/html/v6.6/locking/seqlock.html#api-documentation

标签:seqcount,临界,计数器,序列,ChatGPT,foo,seqlock
From: https://www.cnblogs.com/pengdonglin137/p/17892333.html

相关文章

  • 锁定课程 【ChatGPT】
    https://www.kernel.org/doc/html/v6.6/locking/spinlocks.html锁定课程课程1:自旋锁用于锁定的最基本原语是自旋锁:staticDEFINE_SPINLOCK(xxx_lock);unsignedlongflags;spin_lock_irqsave(&xxx_lock,flags);...临界区域...spin_unlock_irqrestore(&xxx_lock,fl......
  • RT-mutex 实现设计【ChatGPT】
    https://www.kernel.org/doc/html/v6.6/locking/rt-mutex-design.htmlRT-mutex实现设计版权所有(c)2006StevenRostedt根据GNU自由文档许可证第1.2版许可本文档试图描述rtmutex.c实现的设计。它并不描述rtmutex.c存在的原因。有关此内容,请参阅带PI支持的RT-m......
  • 通用互斥子系统 【ChatGPT】
    https://www.kernel.org/doc/html/v6.6/locking/mutex-design.html通用互斥子系统由[email protected]发起由[email protected]更新互斥锁是什么?在Linux内核中,互斥锁指的是一种特定的锁原语,它在共享内存系统上强制进行串行化,而不仅仅是指学术界......
  • 锁统计 【ChatGPT】
    https://www.kernel.org/doc/html/v6.6/locking/lockstat.html锁统计什么顾名思义,它提供了有关锁的统计信息。为什么因为诸如锁争用之类的问题会严重影响性能。如何Lockdep已经在锁函数中设置了钩子,并将锁实例映射到锁类上。我们在此基础上构建(参见运行时锁正确性验证器)......
  • 运行时锁定正确性验证器 【ChatGPT】
    https://www.kernel.org/doc/html/v6.6/locking/lockdep-design.html锁类该验证器操作的基本对象是“锁”的“类”。“锁”的“类”是一组逻辑上相同的锁,即使这些锁可能有多个(可能有成千上万个)实例化。例如,inode结构中的锁是一个类,而每个inode都有自己的该锁类的实例化。验......
  • Locking (ChatGPT)
    原文:https://www.kernel.org/doc/html/latest/locking/index.html锁定锁类型及其规则运行时锁正确性验证器锁统计信息内核锁折磨测试操作通用互斥子系统实时互斥锁实现设计带有PI支持的实时互斥锁子系统序列计数器和顺序锁锁定教训无伤害/等待死锁安全互斥锁设计在......
  • 锁类型及其规则 【ChatGPT】
    https://www.kernel.org/doc/html/latest/locking/locktypes.html锁类型及其规则介绍内核提供了各种锁原语,可以分为三类:睡眠锁CPU本地锁自旋锁本文概念上描述了这些锁类型,并提供了它们的嵌套规则,包括在PREEMPT_RT下的使用规则。锁类别睡眠锁睡眠锁只能在可抢占的......
  • RDMA 控制器 【ChatGPT】
    https://www.kernel.org/doc/html/v6.6/admin-guide/cgroup-v1/rdma.htmlRDMA控制器1.概述1-1.什么是RDMA控制器?RDMA控制器允许用户限制给定一组进程可以使用的RDMA/IB特定资源。这些进程是使用RDMA控制器进行分组的。RDMA控制器定义了可以为cgroup的进程限制......
  • 内存资源控制器实现备忘 【ChatGPT】
    https://www.kernel.org/doc/html/v6.6/admin-guide/cgroup-v1/memcg_test.htmlMemoryResourceController(Memcg)ImplementationMemo最后更新时间:2010/2基础内核版本:基于2.6.33-rc7-mm(34版本的候选版本)。由于虚拟内存变得复杂(其中一个原因是memcg...),memcg的行为也变得......
  • 网络分类器 cgroup 【ChatGPT】
    https://www.kernel.org/doc/html/v6.6/admin-guide/cgroup-v1/net_cls.html网络分类器cgroup网络分类器cgroup提供了一个接口,用于给网络数据包打上一个类别标识符(classid)。流量控制器(tc)可以用来为来自不同cgroup的数据包分配不同的优先级。此外,Netfilter(iptables)也可以......