互斥锁、自旋锁、原子操作的使用场景

这篇具有很好参考价值的文章主要介绍了互斥锁、自旋锁、原子操作的使用场景。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一,互斥锁
原理:

互斥锁属于sleep-waiting类型的锁,例如在一个双核的机器上有两个线程(线程A和线程B),它们分别运行在Core0和Core1上。假设线程A想要通过pthread_mutex_lock操作去得到一个临界区的锁,而此时这个锁正被线程B所持有,那么线程A就会被阻塞,Core0会在此时进行上下文切换(Context Switch)将线程A置于等待队列中,此时Core0就可以运行其它的任务而不必进行忙等待。

适用场景:

因互斥锁会引起线程的切换,效率较低。使用互斥锁会引起线程阻塞等待,不会一直占用这cpu,因此当锁的内容较多,切换不频繁时,建议使用互斥锁

常用API

/*初始化一个互斥锁*/
int pthread_mutex_init(pthread_mutex_t *restrict  mutex,const pthread_mutexattr_t *restrict attr);
参数:
	mutex:互斥锁地址。类型是pthread_mutex_t.
	attr:设置互斥量的属性,通常采用默认属性,即将attr设为NULL。
	可以使用宏PTHREAD_MUTEX_INITALIZER静态初始化互斥锁,如:
	pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;
	这种方法等价于NULL指定的attr参数调用pthread_mutex_init()来完成动态初始化,不同之处在于PTHREAD_MUTEX_INITIALIZER宏不进行错误检查。
返回值:
	成功:0
	失败:非0

/*销毁指定的一个互斥锁,释放资源*/
int pthread_mutex_destroy(pthread_mutex_t *mutex);
参数:
	mutex:互斥锁地址
返回值:
	成功:0
	失败:非0

/*对互斥锁上锁,若互斥锁已经上锁,则调用这阻塞,直到互斥锁解锁后再上锁*/
int pthread_mutex_lock(pthread_mutex_t *mutex)
参数:
	mutex:互斥锁地址
返回值:
	成功:0
	失败:非0

/*对指定的互斥锁解锁*/
int pthread_mutex_unlock(pthread_mutex_t *mutex);
参数:
	mutex:互斥锁地址
返回值:
	成功:0
	失败:非0

二,自旋锁
原理:

Spin lock(自旋锁)属于busy-waiting类型的锁,如果线程A是使用pthread_spin_lock操作去请求锁,那么线程A就会一直在Core0上进行忙等待并不停的进行锁请求,直到得到这个锁为止。自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁。

使用场景:

“自旋锁”的作用是为了解决某项资源的互斥使用。因为自旋锁不会引起调用者睡眠,所以自旋锁的效率远高于互斥锁。因此如果锁的内容较少,阻塞的时间较短,使用自旋锁比较好。

自旋锁一直占用着CPU,他在未获得锁的情况下,一直运行(自旋),所以占用着CPU,如果不能在很短的时间内获得锁,这无疑会使CPU效率降低。因此我们要慎重使用自旋锁,自旋锁只有在内核可抢占式或SMP的情况下才真正需要,在单CPU且不可抢占式的内核下,自旋锁的操作为空操作。自旋锁适用于锁使用者保持锁时间比较短的情况下。

常用API

/*初始化一个自旋锁*/
int pthread_spin_init(pthread_spinlock_t *lock, int pshared);
参数:
	pthread_spinlock_t :初始化自旋锁
	pshared取值:
		PTHREAD_PROCESS_SHARED:该自旋锁可以在多个进程中的线程之间共享。(可以被其他进程中的线程看到)
		PTHREAD_PROCESS_PRIVATE:仅初始化本自旋锁的线程所在的进程内的线程才能够使用该自旋锁。
返回值:
	若成功,返回0;否则,返回错误编号

/*销毁一个锁*/
int pthread_spin_destroy(pthread_spinlock_t *lock);
返回值:
	若成功,返回0;否则,返回错误编号

/*用来获取(锁定)指定的自旋锁. 如果该自旋锁当前没有被其它线程所持有,则调用该函数的线程获得该自旋锁.否则该函数在获得自旋锁之前不会返回。*/
int pthread_spin_lock(pthread_spinlock_t *lock);
返回值:
	若成功,返回0;否则,返回错误编号

/*解锁*/
int pthread_spin_unlock(pthread_spinlock_t *lock);
返回值:
	若成功,返回0;否则,返回错误编号

三、原子操作
所谓原子操作,就是该操作绝不会在执行完毕前被任何其他任务或事件打断,也就说,它的最小的执行单位,不可能有比它更小的执行单位。因此这里的原子实际是使用了物理学里的物质微粒的概念。

原子操作需要硬件的支持,因此是架构相关的,其API和原子类型的定义都定义在内核源码树的include/asm/atomic.h文件中,它们都使用汇编语言实现,因为C语言并不能实现这样的操作。

原子操作主要用于实现资源计数,很多引用计数(refcnt)就是通过原子操作实现的。

四、总结分析
Mutex(互斥锁):

sleep-waiting类型的锁

与自旋锁相比它需要消耗大量的系统资源来建立锁;随后当线程被阻塞时,线程的调度状态被修改,并且线程被加入等待线程队列;最后当锁可用时,在获取锁之前,线程会被从等待队列取出并更改其调度状态;但是在线程被阻塞期间,它不消耗CPU资源。

互斥锁适用于那些可能会阻塞很长时间的场景。

1、 临界区有IO操作

2 、临界区代码复杂或者循环量大

3 、临界区竞争非常激烈

4、 单核处理器

Spin lock(自旋锁):

busy-waiting类型的锁

对于自旋锁来说,它只需要消耗很少的资源来建立锁;随后当线程被阻塞时,它就会一直重复检查看锁是否可用了,也就是说当自旋锁处于等待状态时它会一直消耗CPU时间。

自旋锁适用于那些仅需要阻塞很短时间的场景文章来源地址https://www.toymoban.com/news/detail-409644.html

到了这里,关于互斥锁、自旋锁、原子操作的使用场景的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 一文搞定Linux线程间通讯 / 线程同步方式-互斥锁、读写锁、自旋锁、信号量、条件变量、信号等等

    目录 线程间通讯 / 线程同步方式 锁机制 互斥锁(Mutex) 读写锁(rwlock) 自旋锁(spin) 信号量机制(Semaphore) 条件变量机制 信号(Signal) 线程间通讯 / 线程同步方式 p.s 以下有很多段落是直接引用,没有使用 markdown 的 “引用” 格式,出处均已放出。 参考 / 引用: 100as

    2024年02月10日
    浏览(44)
  • 原子操作的原理和实现

    目录 相关术语 处理器如何实现原子操作 Java如何实现原子操作 循环CAS实现原子操作 使用锁机制实现原子操作 原子操作是指一个或者多个不可再分割的操作。这些操作的执行顺序不能被打乱。 缓存行 :缓存的最小操作单位 (面试题、重点)比较并且交换(CAS) :CAS操作(

    2024年02月10日
    浏览(29)
  • 【Linux从入门到精通】线程互斥与互斥锁的使用与原理详解

      上篇文章我们对线程 | 线程介绍线程控制介绍后,本篇文章将会对多线程中的线程互斥与互斥锁的概念进行详解。同时结合实际例子解释了可重入与不被重入函数、临界资源与临界区和原子性的概念。希望本篇文章会对你有所帮助。 文章目录 引入 一、重入与临界 1、1 可重

    2024年02月07日
    浏览(44)
  • 互斥场景重入锁处理方案

    处理方案一:map+超时重入锁数据结构( 注:该方案并发时可以获取到锁进行操作 ) 核心逻辑模拟--加超时时间 并发问题结果数据 问题 问题:锁对象创建并发问题 处理方案二:map+不超时重入锁数据结构( 注:该方案并发时可以获取到锁进行操作 ) 核心逻辑模拟--不加超时时间 并

    2024年02月10日
    浏览(40)
  • 【Linux】互斥量原理的实现

    深刻理解互斥锁 文章目录 前言 一、 demo版的线程封装 二、 demo版的锁封装 总结 为了实现互斥锁操作 , 大多数体系结构都提供了 swap 或 exchange 指令 , 该指令的作用是把寄存器和内存单元的数据相交换, 由于只有一条指令 , 保证了原子性 , 即使是多处理器平台 , 访问内存的总线

    2024年02月08日
    浏览(26)
  • 【13】STM32·HAL库-正点原子SYSTEM文件夹 | SysTick工作原理、寄存器介绍 | printf函数使用、重定向

      下面函数都是以sys_开头,定义在sys.c中。正点原子函数现阶段命名规则如果是在led.c中,则以led_开头。在F7/H7系列中会存在Cache配置函数,I-Cache中存储指令,D-Cache中存储数据。   SysTick,即系统滴答定时器,包含在M3/4/7内核里面,核心是一个24位的递减计数器( 最大计

    2024年02月15日
    浏览(44)
  • ES 原理和使用场景

    1、比方说,每条记录的指定字段的文本,可能会很长,比如说“商品描述”字段的长度,有长达数千个,甚至数万个字符,这个时候,每次都要对每条记录的所有文本进行扫描。 你包不包含我指定的这个(比如说“牙膏”) 2、还不能将搜索词拆分开来,尽可能去搜索

    2024年01月19日
    浏览(38)
  • Linux pthread线程操作 和 线程同步与互斥操作

    在Linux系统中玩线程,使用pthread,这篇博客记录如何 创建线程 和 使用线程 和线程的 同步 与 互斥 。 还有一份nginx线程池的代码供大家阅读学习! 目录 一、简介 什么是线程 线程的优点、缺点 线程的应用场合 二、线程的使用 1.  创建线程 - pthread_create 2.  线程的终止 - pt

    2024年02月02日
    浏览(31)
  • 22、ThreadLocal的原理和使用场景

    每一个thread对象均含有一个ThreadLocalMap类型的成员变量threadLocals,它存储本线程中所有 ThreadLocal对象及其对应的值 ThreadLocalMap 由一个个Entry对象构成 Entry继承自WeakReferenceThreadLocal?,一个Entry由ThreadLocal对象和Object构成。由此可见,Entry的key是ThreadLocal对象,并且是一个弱引用。

    2024年02月16日
    浏览(58)
  • MySQL事务:原理、类型和使用场景

    一、事务的概念 在数据库中,事务是指一组数据库操作,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单元。事务具有ACID(原子性、一致性、隔离性和持久性)特性,保证了数据库操作的正确性和可靠性。 二、事务的特性 原子性(Atomicity) 原子性是指

    2024年02月02日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包