并发环境下的一些同步方法
一、锁
1. 互斥锁(mutex_lock)
最常使用于线程同步的锁;标记用来保证在任一时刻,只能有一个线程访问该对象,临界区和互斥量都可用来实现此锁,通常情况下锁操作失败会将该线程睡眠等待锁释放时被唤醒。此时有线程切换的消耗。
① 原子性:互斥锁加锁操作是一个原子操作,这保证了如果一个线程锁定了一个互斥量,没有其他线程在同一时间可以成功锁定这个互斥量;
② 唯一性:如果一个线程锁定了一个互斥量,在它解除锁定之前,没有其他线程可以锁定这个互斥量;
③ 非繁忙等待:如果一个线程已经锁定了一个互斥量,第二个线程又试图去锁定这个互斥量,则第二个线程将被挂起(不占用任何cpu资源),直到第一个线程解除对这个互斥量的锁定为止,第二个线程则被唤醒并继续执行,同时锁定这个互斥量。
2. 自旋锁(spin_lock)
与互斥锁相同,除了加锁失败后的后续操作不同。自旋锁加锁失败后并不是睡眠等待唤醒,而是循环检测保持者是否已经释放了锁,不会让出cpu,会一直忙碌。没有线程切换的消耗。
3. 两种锁的适用情况
当锁内执行的操作耗时较少,即等待的消耗远远小于线程切换的消耗,选择自旋锁。
当持有锁的时间比较长时,则选择互斥锁。长时间的自旋操作会给cpu带来非常大的执行开销。
二、原子操作
原子操作的狭义是单条cpu指令实现的操作,广义是指一段不会被线程调度机制打断的操作。
1. C语言用汇编实现+1的原子操作
int inc(int *value, int add) { int old; __asm__ volatile( “lock; xaddl %2, %1;” //xaddl是把%2和%1相加并放到%1里 : “=a” (old) : “m” (*value), “a”(add) : “cc”, “memory” ); return old; }
三、CAS
1. CAS的概念
CAS是Compare And Swap/Compare And Set。CAS是根据乐观锁概念实现的一种无锁同步机制。
线程在读取数据是不进行加锁,在准备修改数据时,先去查询原值,操作的时候比较原值是否被修改,若未被其他线程修改则写入数据,最后返回交互操作是否成功。
常用CAS自旋锁,适用与并发较少的情况。
2. CAS自旋锁的缺点
①ABA问题
ABA问题指线程1获取变量时值为A,此时资源被抢占,线程1休眠,变量值在此期间完成A->B->A的变换操作,线程1被唤醒后判断A与期待值相同,认为A没有被改变过,继续执行交换操作。
具体案例:
- 我们假设一个提款机的例子。假设有一个遵循CAS原理的提款机,小灰有100元存款,要用这个提款机来提款50元。
- 由于提款机硬件出了点问题,小灰的提款操作被同时提交了两次,开启了两个线程,两个线程都是获取当前值100元,要更新成50元。
- 理想情况下,应该一个线程更新成功,一个线程更新失败,小灰的存款值被扣一次。
- 线程1首先执行成功,把余额从100改成50.线程2因为某种原因阻塞。这时,小灰的妈妈刚好给小灰汇款50元。
- 线程2仍然是阻塞状态,线程3执行成功,把余额从50改成了100。
- 线程2恢复运行,由于阻塞之前获得了“当前值”100,并且经过compare检测,此时存款实际值也是100,所以会成功把变量值100更新成50。
- 原本线程2应当提交失败,小灰的正确余额应该保持100元,结果由于ABA问题提交成功了。
解决方法:增加版本号信息,当变量发生变化时,版本号更新,在进行Compare操作时,不仅要比较旧值与期待值,同时也要比较版本号有没有发生改变。
②循环case
CAS自旋锁长时间自旋会消耗大量cpu时间。
解决方法:在低并发的情况下使用;破环自旋的for死循环,增加自旋次数判断,超过次数退出自旋
③只能更新一个值
CAS中只能同时更新一个值
解决方法:加锁;将多个需要改变的值封装成一个对象
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现