互斥机制之自旋锁(spinlock)

2023-11-15

一、(基础)自旋锁

如果测试结果表明锁仍被占用,程序将在一个小的循环内重复这个“测试并设置”操作,即进行所谓的“自旋”。

1.定义自旋锁

spinlock_t spin;

2.初始化自旋锁

spin_lock_init(lock);

//该宏用于动态初始化自旋锁lock。

3.获得自旋锁

spin_lock(lock);

//该宏用于获得自旋锁lock。

//如果能立即获得锁,就马上返回;否则将自旋在那里,直到该自旋锁的保持者释放;

spin_trylock(lock);

//该宏尝试获得自旋锁lock。

//如果能立即获得锁,它获得锁并返回真;否则立即返回假,实际上不再“在原地打转”。

4.释放自旋锁

spin_unlock(lock);

//该宏释放自旋锁lock。

//它与spin_trylock或spin_lock配对使用。

###自旋锁典型用法###

spinlock_t lock; //定义一个自旋锁lock

spin_lock_init(&lock); //初始化自旋锁lock

spin_lock (&lock) ; //获取自旋锁,保护临界区

… //临界区

spin_unlock (&lock) ; //解锁

###自旋锁的衍生###

spin_lock_irq() = spin_lock() + local_irq_disable()

spin_unlock_irq() =spin_unlock() + local_irq_enable()

spin_lock_irqsave() = spin_lock() + local_irq_save()

spin_unlock_irqrestore() = spin_unlock() + local_irq_restore()

spin_lock_bh() =spin_lock() + local_bh_disable()

spin_unlock_bh() =spin_unlock() + local_bh_enable()

二、读写自旋锁(rwlock)

//写操作:只能最多有一个写进程;读操作:同时可以有多个读执行单元;读和写也不能同时进行。

1. 定义和初始化读写自旋锁

rwlock_t my_rwlock;

rwlock_t my_rwlock = RW_LOCK_UNLOCKED; /* 静态初始化*/

rwlock_init(&my_rwlock); /* 动态初始化*/

2.读锁定

void read_lock(rwlock_t *lock);

void read_lock_irqsave(rwlock_t *lock, unsigned long flags);

void read_lock_irq(rwlock_t *lock);

void read_lock_bh(rwlock_t *lock);

3.读解锁

void read_unlock(rwlock_t *lock);

void read_unlock_irqrestore(rwlock_t *lock, unsigned long flags);

void read_unlock_irq(rwlock_t *lock);

void read_unlock_bh(rwlock_t *lock);

//对共享资源进行读取之前,先调用读锁定函数,完成之后调用读解锁函数。

4.写锁定

void write_lock(rwlock_t *lock); int write_trylock(rwlock_t *lock);

void write_lock_irqsave(rwlock_t *lock, unsigned long flags);

void write_lock_irq(rwlock_t *lock);

void write_lock_bh(rwlock_t *lock);

5.写解锁

void write_unlock(rwlock_t *lock);

void write_unlock_irqrestore(rwlock_t *lock, unsigned long flags);

void write_unlock_irq(rwlock_t *lock);

void write_unlock_bh(rwlock_t *lock);

//对共享资源进行读取之前,先调用写锁定函数,完成之后调用写解锁函数。

##读写自旋锁典型用法 ##

rwlock_t lock; //定义rwlock

rwlock_init(&lock); //初始化rwlock

read_lock(&lock); //读时获取锁

… //临界资源

read_unlock(&lock); //写时获取锁

write_lock_irqsave(&lock, flags);

… //临界资源

write_unlock_irqrestore(&lock, flags);

三、顺序锁(seqlock)

//该锁是对读写锁的一种优化,允许读写同时进行;

//写执行单元与写执行单元之间仍然是互斥的;

//读执行单元在读操作期间,写执行单元已经发生了写操作,则读执行单元必须重新读取数据,以便确保得到的数据是完整的;

//限制:要求被保护的共享资源不含有指针!(写执行单元可能使得指针失效)

1.获得顺序锁

void write_seqlock(seqlock_t *sl); int write_tryseqlock(seqlock_t *sl);

write_seqlock_irqsave(lock, flags);

write_seqlock_irq(lock;

write_seqlock_bh(lock);

其中:

write_seqlock_irqsave() = loal_irq_save() + write_seqlock()

write_seqlock_irq() = local_irq_disable() + write_seqlock()

write_seqlock_bh() = local_bh_disable() + write_seqlock()

2.释放顺序锁

void write_sequnlock(seqlock_t *sl);

write_sequnlock_irqrestore(lock, flags);

write_sequnlock_irq(lock);

write_sequnlock_bh(lock);

其中:

write_sequnlock_irqrestore() = write_sequnlock() + local_irq_restore()

write_sequnlock_irq() = write_sequnlock() +local_irq_enable()

write_sequnlock_bh() = write_sequnlock() + local_bh_enable()

##写执行单元使用顺序锁的模式##

write_seqlock(&seqlock_a);

… //写操作代码块

write_sequnlock(&seqlock_a);

##读执行单元使用顺序锁的模式##

do {

seqnum = read_seqbegin(&seqlock_a);

… //读操作代码块

} while (read_seqretry(&seqlock_a, seqnum));

其中:

unsigned read_seqbegin(const seqlock_t *sl); 读开始

int read_seqretry(const seqlock_t *sl, unsigned iv); 重读

另外:

read_seqbegin_irqsave(lock, flags); 读开始

== local_irq_save() + read_seqbegin()

read_seqretry_irqrestore(lock, iv, flags); 重读

== read_seqretry() + local_irq_restore()

四、读-拷贝-更新(RCU)

//可以看做读写锁的高性能版本。既允许多个读执行单元同时访问被保护的数据,又允许多个读执行单元和多个写执行单元同时访问被保护的数据。

//BUT,RCU不能替代读写锁。(因为如果写比较多时,对读执行单元的性能提高不能弥补写执行单元导致的损失)

1.读锁定

rcu_read_lock();

rcu_read_lock_bh();

2.读解锁

rcu_read_unlock();

rcu_read_unlock_bh();

//rcu_read_lock()和rcu_read_unlock()实质: 禁止和使能内核的抢占调度

3.同步RCU

synchronize_rcu();

//由RCU写执行单元调用,将阻塞写执行单元,直到所有的读执行单元已经完成读执行单元临界区,写执行单元才可以继续下一步操作。

//保证所有CPU都处理完正在运行的读执行单元临界区。

4.挂接回调

void
fastcall call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu));

void fastcall call_rcu_bh(struct rcu_head *head, void (*func)(struct rcu_head *rcu));

//由RCU写执行单元调用,不会使写执行单元阻塞,故可以在中断上下文或软中断中使用。

//函数功能:把函数func挂接到RCU回调函数链上,然后立即返回。

5.链表操作函数的RCU版本

//把链表元素new插入到RCU保护的链表head 的开头。

static inline void list_add_rcu(struct list_head *new, struct list_head *head);

//把新的链表元素new添加到被RCU保护的链表的末尾。

static inline void list_add_tail_rcu(struct list_head *new, struct list_head *head);

//从RCU保护的链表中删除指定的链表元素entry。

static inline void list_del_rcu(struct list_head *entry);

//使用新的链表元素new取代旧的链表元素old。

static inline void list_replace_rcu(struct list_head *old, struct list_head *new);

list_for_each_rcu(pos,
head) //该宏用于遍历由RCU保护的链表head。

list_for_each_safe_rcu(pos, n, head) //该宏类似于list_for_each_rcu,不同之处在于它允许安全地删除当前链表元素pos。

list_for_each_entry_rcu(pos, head,member) //该宏类似于list_for_each_rcu,不同之处在于它用于遍历指定类型的数据结构链表;当前链表元素pos为一个包含struct list_head结构的特定的数据结构。

//从由RCU保护的哈希链表中移走链表元素n

static inline void hlist_del_rcu(struct hlist_node *n);

//用于把链表元素n插入到被RCU保护的哈希链表的开头,但同时允许读执行单元对该哈希链表的遍历。

static inline void hlist_add_head_rcu(struct hlist_node *n, struct hlist_head *h);

hlist_for_each_rcu(pos, head) //该宏用于遍历由RCU 保护的哈希链表head。

hlist_for_each_entry_rcu(tpos, pos, head, member) //类似hlist_for_each_rcu(),不同之处在于它用于遍历指定类型的数据结构哈希链表;当前链表元素pos为一个包含struct list_head结构的特定的数据结构。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

互斥机制之自旋锁(spinlock) 的相关文章

随机推荐

  • SAM-DETR学习笔记Accelerating DETR Convergence via Semantic-Aligned Matching

    Abstract 最近开发的DEtection TRansformer DETR 通过消除一系列手工制作的组件 建立了一个新的对象检测范式 然而 DETR的收敛速度非常慢 这大大增加了培训成本 我们观察到 慢收敛主要归因于在不同特征嵌入空间
  • dropout层

    深度神经网 DNN 中经常会存在一个常见的问题 模型只学会在训练集上分类 过拟合现象 dropout就是为了减少过拟合而研究出的一种方法 一 简介 当训练模型较大 而训练数据很少的话 很容易引起过拟合 一般情况我们会想到用正则化 或者减小网
  • EIGamal数字签名的实现(c++)——大三密码学实验

    实验原理 1 密钥产生 Alice要对一个消息签名 她选择一个大素数p和一个本原根g 选择一个秘密整数 并且计算 p g y 公开 x秘密保存 注 EIGamal签名方案的安全性在于x的保密性 由于离散对数学问题难解 很难由 p g y 确
  • 电脑上显示打印机无法连接服务器错误代码,电脑怎么连接打印机显示错误代码的解决办法...

    下面来看看小编为您整理的电脑怎么连接打印机显示错误代码的答案 电脑怎么连接打印机显示错误代码内容导航1 连接不上打印机错误0x00000709 打印机出现0x00000709错误代码可能是因为网络或者打印设置错误 具体解决步骤如下 1 首先
  • 关于APP接口设计

    最近一段时间一直在做APP接口 总结一下APP接口开发过程中的注意事项 1 效率 接口访问速度 APP有别于WEB服务 对服务器端要求是比较严格的 在移动端有限的带宽条件下 要求接口响应速度要快 所有在开发过程中尽量选择效率高的框架 PHP
  • golang获取当前时间,前n天时间,以及时间格式的转化

    获取当前时间 currentTime time Now currentTime 的结果为go的时间time类型 2018 09 27 13 24 58 287714118 0000 UTC 获取前n天的时间 获取两天前的时间 current
  • idea中jar包依赖了但还是找不到类的解决方案

    新项目check到本地 导入到idea中后 编译的时候很多类都报错了 打开发现有些框架中的类找不到 现象为 控制台报错 点击这个包 明明发现是有这个依赖的 说明项目是依赖了这个jar包的 打开项目配置 查看依赖树 问题找到 idea这里将这
  • 机器学习实验基础

    文章目录 一 机器学习是什么 二 实验方法和原则 1 评价指标 1回归任务 2分类任务 3特定任务 2 数据集 3 实验验证 随机重复实验 K fold 交叉实验 三 总结 课程链接 学堂在线 张敏老师机器学习算法训练营 一 机器学习是什么
  • sparkStreaming对接kafka

    ReceiverAPI 需要一个专门的Executor去接收数据 然后发送给其他的Executor做计算 存在的问题 接收数据的Executor和计算的Executor速度会有所不同 特别在接收数据的Executor速度大于计算的Execu
  • shell脚本编程之循环

    内容预知 1 循环的定义 2 for循环 2 1 for循环的基本用法 运用演示1 列表打印 运用演示二 分类打印 运用演示三 累加求和 2 2 for循环读取文件作为循环条件 运用演示 2 3 for循环的多线程运用 运用演示 2 4 f
  • 计算机系统课程 笔记总结 CSAPP第七章 链接(7.1-7.13)

    GitHub计算机系统CSAPP课程资源 计算机系统课程 笔记总结 CSAPP第二章 信息的表示和处理 2 1 2 2 计算机系统课程 笔记总结 CSAPP第二章 信息的表示和处理 2 3 2 4 计算机系统课程 笔记总结 CSAPP第三章
  • Ubuntu复现NeuS(用体绘制学习神经隐式曲面用于多视图重建 )——NeRF应用:表面重建

    目录 一 系统配置 二 安装 可能会遇到的问题 1 pytorch安装报错 2 缺少安装依赖项 三 数据集文件夹设置 1 数据集链接 2 数据集组织 3 以dtu scan24为例 四 训练 以dtu scan24为例 1 无掩码训练 2
  • 在Linux系统中部署zabbix监控服务

    今天学习安装zabbix 以下参考网上各种安装方法及自己做实验 一 zabbix简介 zabbix z biks 是一个基于WEB界面的提供分布式系统监视以及网络监视功能的企业级的开源解决方案 zabbix能监视各种网络参数 保证服务器系统
  • 查找---散列表查找定义

    当我们进行查找时 如果是顺序表查找 要找的关键字的记录 是从表头开始 挨个的比较记录a i 与key的值是等于还是不等于 有序表查找时 利用折半查询或者插值查询 直到相等时成功返回i 最终我们的目的都是为了找到那个i 其实也就是相对的下标
  • 使用TortoiseGit

    初衷 脱离命令行的方式 使用gui的界面化工具完成工作需要的版本控制操作 同时还对git运行机制有一定的了解 达到工作需要的基本 提高工作效率 准备工作 安装git 至于为什么 我就不废话了 点我下载git 安装TortoiseGit 理由
  • 【vue3引入高德地图】

    vue3引入高德地图 文章目录 vue3引入高德地图 前言 一 准备工作 1 开发文档 2 添加应用 二 使用步骤 1 npm 安装 2 地图容器创建 3 组件引入 4 js api 安全密钥 5 初始化地图 6 图层 6 1 添加 设置
  • 在 Windows 10 编译 Qt 5.15

    译好的下载链接 Qt5 15 8 Windows x86 VS2017 Qt5 15 8 Windows x86 64 VS2017 Qt5 15 8 Windows x86 VS2019 Qt5 15 8 Windows x86 64 V
  • 【Unity】通过代码控制编译器的暂停

    暂停编译器 EditorApplication isPaused true 结束编译器 EditorApplication isPlaying false
  • sklearn决策树之random_state & splitter

    在上一篇博文 决策树的sklearn实现 中 我们建立了一棵完整的决策树 但是如果在建立模型时不设置random state的数值 score会在某个值附近波动 引起画出来的每一棵树都 一样 它为什么会 稳定呢 如果使用其他数据集 它还会不
  • 互斥机制之自旋锁(spinlock)

    一 基础 自旋锁 如果测试结果表明锁仍被占用 程序将在一个小的循环内重复这个 测试并设置 操作 即进行所谓的 自旋 1 定义自旋锁 spinlock t spin 2 初始化自旋锁 spin lock init lock 该宏用于动态初始化