Linux内核中的锁

不同的锁,作用对象是不一样的,也就是作用域不一样
下面分别是作用于临界区CPU内存cache 的各种锁的归纳:
补充:cache是一种缓存,包含硬件缓存(CPU缓存)以及软件缓存(网页缓存,数据缓存)
补充:临界区用于描述一段只能被单个线程或进程在同一时间访问的代码区域。通常,这些代码区域涉及对共享资源的访问
临界区 -> semaphore信号量、Mutex互斥锁、rw-lock读写锁、preempt抢占
CPU -> atomic原子变量、spinlock自旋锁
内存 -> RCU 、Memory Barrier
cache -> Per-CPU

一、atomic原子变量/spinlock自旋锁 — —CPU

既然是锁CPU那就都是针对多核处理器或多CPU处理器。单核的话,只有发生中断会使任务被抢占,那么可以进入临界区之前先关中断,但是对多核CPU光关中断就不够了,因为对当前CPU关了中断只能使得当前CPU不会运行其它要进入临界区的程序,但其它CPU还是可能执行进入临界区的程序。

(1) atomic原子变量:
所谓原子操作, 就是该操作绝不会在执行完毕前被任何其他任务或事件打断
, 也就说, 它是最小的执行单位, 不可能有比它更小的执行单位, 因此这里的原子实际是使用了物理学里的物质微粒的概念。原子操作需要硬件的支持, 因此是架构相关的, 其 API 和原子类型的定义都定义在内核源码树的 include/asm/atomic.h 文件中, 它们都使用汇编语言实现, 因为 C 语言并不能实现这样的操作。原子操作主要用于实现资源计数, 很多引用计数 (refcnt) 就是通过原子操作实现的。
(2) spinlock自旋锁:

当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待然后不断的判断锁是否能够被成功获取

#include <linux/spinlock.h>
// 定义自旋锁
spinlock_t my_lock;
void my_function(void)
{spin_lock(&my_lock);// 访问共享资源的操作spin_unlock(&my_lock);
}

ps:针对上述进行一些重要问题的阐述,如下所示

互斥锁中,要是当前线程没拿到锁,就会出让CPU;而自旋锁中,要是当前线程没有拿到锁,当前线程在CPU上忙等待直到锁可用,这是为了保证响应速度更快。但是这种线程多了,那意味着多个CPU核都在忙等待,使得系统性能下降。

因此一定不能自旋太久,所以用户态编程里用自旋锁保护临界区的话,这个临界区一定要尽可能小,锁的粒度得尽可能小。

为什么自旋锁的响应速度会比互斥锁更快?

我觉得主要还是作用域的问题 spinlock 主要针对CPU 互斥锁针对作用域 前者直接CPU操作 后者需要内核协助 在小林coding中说到,自旋锁是通过 CPU 提供的 CAS 函数(Compare And Swap),在「用户态」完成加锁和解锁操作,不会主动产生线程上下文切换,所以相比互斥锁来说,会快一些,开销也小一些。 而互斥锁则不是,前面说互斥锁加锁失败,线程会出让CPU,这个过程其实是由内核来完成线程切换的,因此加锁失败时,1)首先从用户态切换至内核态,内核会把线程的状态从「运行」状态设置为「睡眠」状态,然后把 CPU 切换给其他线程运行;2)当互斥锁可用时,之前「睡眠」状态的线程会变为「就绪」状态(要进入就绪队列了),之后内核会在合适的时间,把 CPU 切换给该线程运行。 然后返回用户态。这个过程中,不仅有用户态到内核态的切换开销,还有两次线程上下文切换的开销。 线程的上下文切换主要是线程栈、寄存器、线程局部变量等。 而自旋锁在当前线程获取锁失败时不会进行线程的切换,而是一直循环等待直到获取锁成功。因此,自旋锁不会切换至内核态,也没有线程切换开销。 所以如果这个锁被占有的时间很短,或者说各个线程对临界区是快进快出,那么用自旋锁是开销最小的! 自旋锁的缺点前面也说了,就是如果自旋久了或者自旋的线程数量多了,CPU的利用率就下降了,因为上面执行的每个线程都在忙等待— —占用了CPU但什么事都没做。

二、信号量/互斥锁 读写锁/抢占 — —临界区

(1) semaphore信号量

其实跟FreeRTOS的信号量很像很像!!但是RTOS得信号量是队列的变种,而linux下的信号量是利用spinlock的保护

信号量(信号灯)本质是一个计数器,是描述临界区中可用资源数目的计数器。

信号量进行多线程通信编程的时候,往往初始化信号量为0,然后用两个函数做线程间同步: sem_wait():等待信号量,如果信号量的值大于0,将信号量的值减1,立即返回。 如果信号量的值为0,则线程阻塞。 sem_post():释放资源,信号量+1 ,相当于unlock,这样执行了sem_wait()的线程就不阻塞了。

要注意:信号量本身也是个共享资源,它的++操作(释放资源)和--操作(获取资源)也需要保护。其实就是用的自旋锁保护的。如果有中断的话,会把中断保存到eflags寄存器,待操作完成,就去该寄存器上读取,然后执行中断。

(2) Mutex互斥锁

互斥锁中,要是当前线程没拿到锁,就会出让CPU;而自旋锁中,要是当前线程没有拿到锁,当前线程在CPU上忙等待直到锁可用

信号量的话表示可用资源的数量,是允许多个进程/线程在临界区的。但是互斥锁不是,它的目的就是只让一个线程进入临界区,其余线程没拿到锁,就只能阻塞等待。线程互斥的进入临界区,这就是互斥锁名字由来。

另外提一下std::timed_mutex睡眠锁,它和互斥锁的区别是: 互斥锁中,没拿到锁的线程就一直阻塞等待,而睡眠锁则是设置一定的睡眠时间比如2s,线程睡眠2s,如果过了之后还没拿到锁,那就放弃拿锁(可以输出获取锁失败),如果拿到了,那就继续做事。比如 用成员函数try_lock_for()

std::timed_mutex g_mutex;
//先睡2s再去抢锁
if(g_mutex.try_lock_for(std::chrono::seconds(2)))){// do something
}
else{// 没抢到std::cout<<"获取锁失败";
}

(3) rw-lock读写锁

用于读操作比写操作更频繁的场景,让读和写分开加锁,这样可以减小锁的粒度,提高程序的性能。 它允许多个线程同时读取共享资源,但只允许一个线程写入共享资源。这可以提高并发性能,因为读操作通常比写操作频繁得多。读写锁这种就属于高阶锁了,它的实现就可以用自旋锁。

(4) preempt抢占

抢占必须涉及进程上下文的切换,而中断则是涉及中断上下文的切换。 内核从2.6开始就支持内核抢占,之前的内核不支持抢占,只要进程在占用CPU且时间片没用完,除非有中断,否则它就能一直占用CPU; 抢占的情况: 比如某个优先级高的任务(进程),因为需要等待资源,就主动让出CPU(又或者因为中断被打断了),然后低优先级的任务先占用CPU,当资源到了,内核就让该优先级高的任务抢占那个正在CPU上跑的任务。也就是说,当前的优先级低的进程跑着跑着,时间片没用完,也没发生中断,但是自己被踢掉了。 为了支持内核抢占,内核引入了preempt_count字段,该计数初始值为0,每当使用锁时+1,释放锁时-1。当preempt_count为0时,表示内核可以安全的抢占,大于0时,则禁止内核抢占

Per-CPU— —作用于cache per-cpu变量用于解决各个CPU里L2 cache和内存间的数据不一致性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/27855.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Cocos2d-x 4.0 工程首次建立与编译(Mac m1)

Mac m1芯片下将cocos2d-x升级至4.0版本后&#xff0c;官方剔除了不同平台的工程以及变更了编译方式&#xff0c;直接使用cmake构建&#xff0c;需要做一些前置的准备工作。 环境准备&#xff1a; 项 版本 备注 MacOS10.3 or laterpython2.7.16(建议>2.7.10)cmake3.29.3Do…

自动驾驶场景下TCP协议参数优化调整案例分享

RTT 往返时间&#xff0c;从tcp协议栈决定发包&#xff0c;到收到回包的时间。 包含本地驱动&#xff0c;网卡硬件&#xff0c;网线&#xff0c;交换机&#xff0c;收包方处理的耗时。需注意如果开了delayed ack&#xff0c;协议栈未做特殊处理&#xff08;默认没做&#xff…

C++中字符字面量的使用细节

C中字符字面量的使用细节 如何在 C中书写字符字面值:将字符用单引号括起&#xff0c;如M(注意&#xff0c;示例中没有使用双引号。C对字符用单引号&#xff0c;对字符串使用双引号。cout对象能够处理这两种情况&#xff0c;但正如第4章将讨论的&#xff0c;这两者有天壤之别)。…

【项目管理知识】挣值管理的概念与计算

【项目管理知识】挣值管理的概念与计算 四个基础概念&#xff1a;BAC、AC、PV、EV四个绩效概念&#xff1a;CV、CPI、SV、SPI四个延伸概念&#xff1a;ETC、EAC、非典型偏差、典型偏差挣值管理-非典型偏差挣值管理-典型偏差 完工尚需绩效指数&#xff1a;TCPI 四个基础概念&…

探索交互的本质:从指令到界面的演进与Linux基础指令的深入剖析

目录 1.指令 vs 界面//选读 1.1交互的需求 满足需求的第一阶段-指令 满足需求的第二阶段-界面 1.2 指令 和 界面交互 区别 2.操作系统介绍 2.1 举例说明 驱动软件层 2.2 为什么要有操作系统&#xff1f; 0x03 为什么要进行指令操作&#xff1f; 3.Linux基本指令 l…

模型量化 剪枝bevfusion

量化 剪枝 shared mem 只在block内共享&#xff0c;device glob mem能够所有线程共享

从多线程设计模式到对 CompletableFuture 的应用

大家好&#xff0c;我是 方圆。最近在开发 延保服务 频道页时&#xff0c;为了提高查询效率&#xff0c;使用到了多线程技术。为了对多线程方案设计有更加充分的了解&#xff0c;在业余时间读完了《图解 Java 多线程设计模式》这本书&#xff0c;觉得收获良多。本篇文章将介绍其…

重塑IT审计的未来:数智化审计赋能平台的创新与实践

重塑IT审计的未来&#xff1a;数智化审计赋能平台的创新与实践 一、当前企业开展IT审计面临的挑战 随着信息技术的快速发展、企业数字化转型的持续深入&#xff0c;以及网络安全合规要求的不断增强&#xff0c;企业开展新型IT审计重要性越来越突出&#xff0c;但实施难度却越来…

859.亲密字符串

给你两个字符串 s 和 goal &#xff0c;只要我们可以通过交换 s 中的两个字母得到与 goal 相等的结果&#xff0c;就返回 true &#xff1b;否则返回 false 。 交换字母的定义是&#xff1a;取两个下标 i 和 j &#xff08;下标从 0 开始&#xff09;且满足 i ! j &#xff0c…

【数据融合】基于卡尔曼滤波实现GPS-IMU数据融合附matlab代码

下面是一个简单的示例代码&#xff0c;用于基于卡尔曼滤波实现GPS-IMU数据融合的MATLAB实现&#xff1a; matlab % 初始化卡尔曼滤波器参数 dt 0.1; % 时间步长 A [1 dt; 0 1]; % 状态转移矩阵 B [0.5*dt^2; dt]; % 输入控制矩阵 H [1 0]; % 观测矩阵 Q eye(2); % 状态噪…

Python闯LeetCode--第2题:两数相加

Problem: 2. 两数相加 文章目录 思路解题方法复杂度Code 思路 看到这一题&#xff0c;第一反应是分别遍历两个链表&#xff0c;用列表来存储数&#xff0c;先把两个数的值拿到&#xff0c;转为具体数之后进行相加&#xff0c;再把两数相加值转为列表&#xff0c;再转为链表返回…

统计信号处理基础 习题解答10-16

题目&#xff1a; 对于例10.1&#xff0c;证明由观察数据得到的信息是&#xff1a; 解答&#xff1a; 基于习题10-15的结论&#xff0c;&#xff0c;那么&#xff1a; 而根据习题10-15的结论&#xff1a; 此条件概率也是高斯分布&#xff0c;即&#xff1a; 根据相同的计算&a…

国密SM2JS加密后端解密

1.前端加密 前端加密开源库 sm-crypto 1.1 传统web,下载 sm-crypto 进行打包为 dist/sm2.js 相关打包命令 npm install --save sm-crypto npm install npm run prepublish在web页面引用打包后的文件 <script type"text/javascript" src"<%path %>…

一文带你搞清楚AI领域的高频术语!RAG、Agent、知识库、向量数据库、知识图谱、Prompt...都是在讲啥?

随着AI人工智能技术的不断发展&#xff0c;一些领域有关的概念和缩写总是出现在各种文章里&#xff0c;像是Prompt Engineering、Agent 智能体、知识库、向量数据库、RAG 以及知识图谱等等&#xff0c;但是这些技术和概念也的的确确在AI大模型的发展中扮演着至关重要的角色。这…

使用 3D 图形 API 在 C# 中将 PLY 转换为 OBJ

OBJ和PLY是一些广泛使用的 3D 文件格式&#xff0c;易于编写和读取。这篇博文演示了如何以编程方式在 C# 中将 PLY 转换为 OBJ。此外&#xff0c;它还介绍了一种用于 3D 文件格式转换的在线3D 转换器。是的&#xff0c;Aspose.3D for .NET为程序员和非程序员提供了此功能来执行…

Day52 代码随想录打卡|二叉树篇---二叉搜索树中的众数

题目&#xff08;leecode T501&#xff09;&#xff1a; 给你一个含重复值的二叉搜索树&#xff08;BST&#xff09;的根节点 root &#xff0c;找出并返回 BST 中的所有 众数&#xff08;即&#xff0c;出现频率最高的元素&#xff09;。 如果树中有不止一个众数&#xff0c…

【深度学习】基于EANet模型的图像识别和分类技术

1.引言 1.1.EANet模型简介 EANet&#xff08;External Attention Transformer&#xff09;是一种深度学习模型&#xff0c;它结合了Transformer架构和外部注意力机制&#xff0c;特别适用于图像分类等计算机视觉任务。以下是关于EANet的详细解释&#xff1a; 1.1.1 定义与背…

微信小程序写一个录音机

微信小程序写一个录音机 代码&#xff1a; wxml: <view class"container"><view class"duration">{{duration}}</view><button bindtap"startRecord" class"btn">开始录音</button><button bindta…

Node.js版本管理工具-NVM

在开发 Node.js 项目时&#xff0c;经常会遇到需要切换不同版本的 Node.js 的情况。为了方便管理和切换各个版本&#xff0c;我们可以使用一些 Node.js 版本管理工具。 Node Version Manager&#xff1a;简称NVM&#xff0c;最流行的 Node.js 版本管理工具之一。它允许我们在同…

计算机体系结构重点学习(一)

从外部I/O与上层应用交互的整体软硬件过程 上层应用发出I/O请求&#xff1a;上层应用程序&#xff0c;如一个文本编辑器、网络浏览器或者任何软件应用&#xff0c;需要读取或写入数据时&#xff0c;会通过调用操作系统提供的API&#xff08;如文件操作API、网络操作API等&…