Linux内核之 内核同步

 

一、同步介绍

 

1、临界区与竞争条件

所谓临界区(critical regions)就是访问和操作共享数据的代码段。为了避免在临界区中并发访问,编程者必须保证这些代码原子地执行——也就是说,代码在执行结束前不可被打断,就如同整个临界区是一个不可分割的指令一样。如果两个执行线程有可能处于同一个临界区中同时执行,那么就是程序包含一个bug,如果这种情况发生了,我们就称之为竞争条件(race conditions,简称竞态),避免并发和防止竞争条件被称为同步(synchronization)。

在linux中,主要的竞态发生在如下几种情况:

(1)对称多处理器(SMP)多个CPU

特点是多个CPU使用共同的系统总线,因此可访问共同的外设和存储器。

(2)单CPU内进程与抢占它的进程

(3)中断(硬中断、软中断、Tasklet、中断下半部)与进程之间

只要并发的多个执行单元存在对共享资源的访问,竞态就有可能发生。

如果中断处理程序访问进程正在访问的资源,则竞态也会发生。

多个中断之间本身也可能引起并发而导致竞态(中断被更高优先级的中断打断)。

互斥锁,自旋锁,CAS,原子操作详细说明点击:「链接」

2、死锁

死锁的产生需要一定条件:要有一个或多个执行线程和一个或多个资源,每个线程都在等待其中的一个资源,但所有的资源都已经被占用了,所有线程都在相互等待,但它们永远不会释放已经占有的资源,于是任何线程都无法继续,这便意味着死锁的发生。

最简单的死锁例子是自死锁:

  • 获得锁

  • 再次试图获得锁

  • 等待锁重新利用

  • ......

这种情况属于一个线程一把锁,自己等自己,一般是一个函数等另一个函数,从广义上说就是一种嵌套使用。我曾经的经验总结《踩坑经验总结(四):死锁》就属于这种情况。

最常见的死锁例子是ABBA锁:

  • 线程1

  • 获得锁A

  • 试图获得锁B

  • 等待锁B

  • ......

  • 线程2

  • 获得锁B

  • 试图获得锁A

  • 等待锁A

  • ......

这种问题确实很常见,在数据库《MySQL InnoDB技术内幕:内存管理、事务和锁》出现的往往也是这种类型的死锁。

3、加锁规则

预防死锁非常重要,那该注意些什么呢?

(1)按顺序加锁。使用嵌套锁是必须保证以正确的顺序获取锁,这样可以阻止致命的拥抱类死锁,即ABBA锁。最好能记录下锁的顺序,后续都按此顺序使用。

(2)防止发生饥饿。特别是在一些大循环中,尽量将锁移入内部,否则外面等太久。如果发生死循环,就会出现饥饿。

(3)不要重复请求同一把锁。这是针对自死锁的情况,但是一旦出现这种情况,往往不明显,即不是很明显的嵌套,转了几个弯弯,就叫曲线嵌套吧。

(4)设计应力求简单。越复杂的加锁方案越有可能造成死锁。

这里的每一项都很重要,对于应用程序同样适合。再重点说下设计。

在最开始设计代码的时候,就应该考虑加锁;越往后考虑,付出代价越大,效果反而越不理想。那么设计阶段加锁时一定要考虑,为什么要加锁,为了保护什么数据?我认为这是一个定位的问题。需求阶段对一个产品的定位,设计阶段对数据的定位,决定了后续一系列的

  • 7
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值