互斥机制之自旋锁(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) 的相关文章

  • 海思芯片上GPIO和PWM操作

    一 GPIO的配置 GPIO的设置一般为三步 1 设置gpio端口复用 2 设置GPIO口的方向 3 读取或者写入GPIO值 第一步不是每个GPIO口都是要配置的 如果你设置的GPIO端口有复用功能 那么你需要对GPIO对应复用寄存器进行配
  • 读spi_flash的id

    读SPI FLASH的ID 在上一课中spi i2c adc OLED文件夹下添加spi flash c及spi flash h文件 并添加到si工程中 明确目的 在main函数中调用函数读取spiflash的厂家ID和设备ID 并打印 明
  • Linux下生成patch和打patch

    通过diff工具生成补丁 patch工具打上补丁 在使用diff之前 你需要保留一份未修改过的源码 然后在其它地方修改源码的一份拷贝 diff对比这两份源码生成patch 修改过的源码必须保留原来的文件名 例如 如果你修改源码中的a c文件
  • linux内核的自旋锁spin_lock和互斥锁mutex_lock

    访问共享资源的代码区域称作临界区 自旋锁 spin lock 和互斥锁 mutex lock 是保护内核临界区的两种基本机制 我们逐个分析 自旋锁可以确保在同时只有一个线程进入临界区 其他想进入临界区的线程必须不停地原地打转 直到第1个线程
  • 嵌入式Linux子系统之网络子系统网卡驱动分析

    嵌入式Linux子系统之网络子系统网卡驱动分析 重要数据结构 struct net device 描述网卡驱动的结构 struct net device ops 设备操作统一接口操作集 struct sk buff 网络数据包描述结构 一般
  • 重装ubuntu后Samba从windows不能登录

    Samba登录问题 ubuntu被搞挂了 重装了下 apt get samba后导入之前的smb conf竟然在windows里无法登录 折腾了几个小时后突然发现sb服务器竟然没有从linux里自动倒入密码 所以如下路径 新装ubuntu后
  • VMware player桥接模式不能联网的解决方法

    VMware虚拟机下主要使用两种网络连接方式 桥接模式 NAT模式 桥接模式 直接连接网络 虚拟机独立IP 并与宿主机处于同一网段内 相当于虚拟机是局域网内独立的一台电脑 使用起来较为方便 NAT模式 网络地址转换 借由宿主机的IP访问网络
  • 内存、ram、sram、dram、rom、eprom、epprom、flash、norflash、nandflash 的比较

    1 内存 什么是内存呢 在计算机的组成结构中 有一个很重要的部分 就是存储器 存储器是用来存储程序和数据的部件 对于计算机来说 有了存储器 才有记忆功能 才能保证正常工作 存储器的种类很多 按其用途可分为主存储器和辅助存储器 主存储器又称内
  • 基于嵌入式Qt的输入法syszuxpinyin自动弹出软件盘的问题

    移植好的syszuxpinyin输入法能正常的检测到控件焦点并自动弹出软键盘 当使用默认的QLineEdit控件时就有了一些小小的问题 问题一 QLineEditt在默认情况下会自动出现焦点 从而导致一进入界面就弹出软键盘 但是我们需要点击
  • 互斥机制之自旋锁(spinlock)

    一 基础 自旋锁 如果测试结果表明锁仍被占用 程序将在一个小的循环内重复这个 测试并设置 操作 即进行所谓的 自旋 1 定义自旋锁 spinlock t spin 2 初始化自旋锁 spin lock init lock 该宏用于动态初始化
  • 从CPU cache一致性的角度看Linux spinlock的不可伸缩性(non-scalable)

    凌晨一点半的深圳雨夜 豪雨当夜惊起有人赏 笑叹落花无声空飘零 喜欢这种豪雨 让人兴奋 惊起作文以呜呼之感叹 引用上一篇文章 优化多核CPU的TCP新建连接性能 重排spinlock https blog csdn net dog250 ar
  • 嵌入式Linux——oops:根据oops信息,找到错误的产生位置以及函数的调用关系

    简介 本文主要介绍通过oops信息找到程序中出错位置的方法 并结合自己代码中的错误来讲解如何找到出错位置 同时还会介绍使用栈信息来推到函数间的调用关系 Linux内核 linux 2 6 22 6 所用开发板 JZ2440 V3 S3C24
  • TQ2440移植u-boot2016.11全过程记录-【1】单板建立并启动

    TQ2440移植u boot2016 11 单板建立并启动 移植说明 u boot2016 11是S3C2440最后一版的uboot支持 所以选择了此版本进行移植 交叉编译器使用的是天嵌官方的交叉编译器 版本为4 4 3 使用的ubuntu
  • 嵌入式Linux编译系统的设计——Bootloader, 内核,驱动,文件系统,升级镜像等自动化编译打包

    项目简介 嵌入式系统的开发过程较为复杂 编译 裁剪 定制等如果没有一套规范的流程将会难于管理和控制 本项目的目的是设计一个嵌入式Linux编译系统 实现代码的编译 定制和裁剪 Bootloader 内核 驱动 文件系统 升级镜像等都可以自动
  • linux下绑定任务到特定的CPU

    一 linux c查看cpu核 1 命令行查看cpu有几个核 cat proc cpuinfo grep processor wc l 或 nproc 2 linux c代码查看 include
  • 为什么每个人都说 SpinLock 更快? [关闭]

    很难说出这里问的是什么 这个问题模棱两可 含糊不清 不完整 过于宽泛或言辞激烈 无法以目前的形式合理回答 如需帮助澄清此问题以便重新打开 访问帮助中心 我在互联网上阅读了很多文档 文章和帖子 几乎每个地方的每个人都认为 SpinLock 对
  • 如何实现自旋锁以避免阻塞

    考虑以下代码 Below block executed by thread t1 synchronized obj obj wait 0 This block executed by thread t2 synchronized obj o
  • 通过内联汇编锁定内存操作

    我对低级的东西很陌生 所以我完全不知道你可能会遇到什么样的问题 我什至不确定我是否正确理解 原子 一词 现在我正在尝试通过扩展程序集围绕内存操作制作简单的原子锁 为什么 为了好奇心 我知道我正在重新发明轮子 并且可能过度简化了整个过程 问题
  • 我什么时候应该和不应该使用这个 C# 实用程序类通过 Interlocked 控制线程

    我试图理解这个类的编写方式背后的逻辑 以及何时应该和不应该使用它 任何见解将不胜感激 internal struct SpinLock private volatile int lockHeld private readonly stati
  • 自旋锁在单处理器单核架构中有用吗?

    我对自旋锁的功能感到困惑 自旋锁用于阻止进程重新调度 然而 在只有一个核心的机器上 使用自旋锁有用吗 防止上下文切换 您的观察结果很好 在单处理器系统上 旋转等待资源是没有意义的 因为您最好尽早切换线程 互斥体和信号量正是这样做的 在多处理

随机推荐

  • 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 该宏用于动态初始化