互斥锁,自旋锁,原子操作的原理,区别和实现

简介: v互斥锁,自旋锁,原子操作的原理,区别和实现

一,互斥锁

原理:

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

适用场景:

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

 

互斥锁的特点:

(1)唯一性:如果一个线程锁定了一个互斥量,在它解除锁定之前,没有其他线程可以锁定这个互斥量;

(2)原子性:把一个互斥量锁定为一个原子操作,这意味着操作系统(或pthread函数库)保证了如果一个线程锁定了一个互斥量,没有其他线程在同一时间可以成功锁定这个互斥量;

(3)非繁忙等待:如果一个线程已经锁定了一个互斥量,第二个线程又试图去锁定这个互斥量,则第二个线程将被挂起(不占用任何cpu资源),直到第一个线程解除对这个互斥量的锁定为止,第二个线程则被唤醒并继续执行,同时锁定这个互斥量。

使用方法:

/*初始化一个互斥锁*/
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且不可抢占式的内核下,自旋锁的操作为空操作。自旋锁适用于锁使用者保持锁时间比较短的情况下。

使用方法:

/*初始化一个自旋锁*/
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时间。

自旋锁适用于那些仅需要阻塞很短时间的场景

 

目录
相关文章
|
Rust 算法 网络安全
【密码学】一文读懂CMAC
介于上一篇文章比较水,然后这个和上一篇也比较相似,CMAC是为了解决DAA当中安全性不足的问题而出现的,这个算法一共有三个密钥,K, K1, K2, 其中K1和K2可以由K导出,接下来就来一起看一下CMAC的具体过程吧,这一篇文章其实也不长。
5895 0
【密码学】一文读懂CMAC
|
移动开发 前端开发 JavaScript
|
12月前
|
数据采集 SQL 分布式计算
数据清洗,必须掌握的5大解决方案+4大步骤
数据模型出错、报表对不上?根源常在于数据清洗。本文系统解析数据清洗的应用场景、核心步骤与常见痛点,并介绍如何通过FineDataLink等工具实现高效自动化清洗,将杂乱原始数据转化为高质量分析基石,提升数据可靠性与分析效率。
数据清洗,必须掌握的5大解决方案+4大步骤
|
11月前
|
人工智能 移动开发 小程序
市面上的小程序平台对比
市面上的小程序平台对比
1659 138
|
存储 缓存 监控
Redis分区的核心原理与应用实践
Redis分区通过将数据分散存储于多个节点,提升系统处理高并发与大规模数据的能力。本文详解分区原理、策略及应用实践,涵盖哈希、范围、一致性哈希等分片方式,分析其适用场景与性能优势,并探讨电商秒杀、物联网等典型用例,为构建高性能、可扩展的Redis集群提供参考。
575 0
SVN常用命令
本文汇总了SVN版本控制系统的常用命令,包括代码检出、提交、更新、添加、删除、查看日志、状态、差异比较、撤销修改、忽略设置、清理、查看信息、文件列表、文件内容查看、blame操作、地址重定向以及分支管理等,旨在帮助用户更高效地使用SVN进行代码版本控制。
|
网络协议 算法 网络性能优化
C语言 网络编程(十五)套接字选项设置
`setsockopt()`函数用于设置套接字选项,如重复使用地址(`SO_REUSEADDR`)、端口(`SO_REUSEPORT`)及超时时间(`SO_RCVTIMEO`)。其参数包括套接字描述符、协议级别、选项名称、选项值及其长度。成功返回0,失败返回-1并设置`errno`。示例展示了如何创建TCP服务器并设置相关选项。配套的`getsockopt()`函数用于获取这些选项的值。
931 12
|
传感器 Linux API
远程处理器消息框架(RPMSG) 【ChatGPT】
远程处理器消息框架(RPMSG) 【ChatGPT】
|
数据处理
epoll的水平触发(LT)和边缘触发模式(ET)详解
epoll的水平触发(LT)和边缘触发模式(ET)详解
1123 0

热门文章

最新文章