linux内核并发控制-互斥体、自旋锁、中断屏蔽

原创 2018年04月17日 14:02:21

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

1.对称多处理器(SMP)的核间并发

cpu0的进程/中断与cpu1的进程\中断之间的并行。

2.单cpu内进程与抢占它的进程

进程与抢占它的进程访问共享资源类似于SMP的多个cpu

3.中断与进程之间(核间或核内并发)

中断可以打断正在执行的进程,如果中断服务程序访问进程正在访问的资源,则竞态也会发生。linux2.6.35之后就取消了中断的嵌套,所以核内没有中断嵌套引起的并发,核间可能有中断与中断的并行。

解决竞态问题的途径是保证对共享资源的互斥访问,所谓互斥访问是指一个执行单元在访问共享资源时,其他的执行单元被禁止访问。访问共享资源的代码区域被称为临界区。中断屏蔽、自旋锁、互斥体是常用的互斥手段。

一 中断屏蔽

中断屏蔽local_irq_disable()和中断使能local_irq_enablle()都只能禁止和使能本cpu内的中断。所以中断屏蔽可以使得核内的中断与进程并发不再发生,由于linux进程调度依赖中断来实现,进程与抢占它的进程之间的并发也避免了。但不能解决SMP多cpu引发的竞态。所以屏蔽中断来避免竞态不是一种正确的做法。

local_irq_disable()//屏蔽中断
...
critical section//临界区
...
local_irq_enable()//使能中断

二 自旋锁

spin_lock():任何一个核拿到自旋锁,该核上的进程抢占调度就被禁止了,但是没有禁止其他核的抢占调度,由于锁的存在,可以保证临界区不受别的cpu或本cpu内的抢占进程打扰。

但是得到锁的代码路径在执行临界区时,还可能收到中断和底半部的影响。

spin_lock_irq=spin_lock+local_irq_disable 锁+关闭本核中断

spin_unlock_irq=spin_unlock+local_irq_enable

spin_lock_irqsave=spin_lock+local_irq_save

spin_locj_irqrestore=spin_unlock+local_irq_restore

spin_lock_bh = spin_lock+local_bh_disable

spin_unlock_bh = spin_unlock+local_bh_enable

如果进程和中断可能访问同一片资源,一般需要在进程上下文中使用spin_lock_irqsave/spin_unlock_irqrestore,避免核内进程与中断并发。在中断上下文中使用spin_lock/spin_unlock,避免核间中断与进程/中断并发。

自旋锁使用注意:占用锁的时间应该很短,即临界区域应很简短;自旋锁锁定期间不能调用可能引起进程调度的函数如copy_from_user/copy_to_user/kmalloc/msleep,其实就是进程获得锁之后,自己不能阻塞,因为阻塞后进程无法再调度;

spin_lock_t lock;
spin_lock_init(lock);
spin_lock(lock)
...
临界区
...
spin_unlock

if (spin_trylock(lock)) {
    ...//获得锁
    临界区
    spin_unlock(lock);
}
else {
    //没有获得锁,不需要解锁
}

//禁止本核进程调度,屏蔽本核中断,保存状态
spin_lock_irqsave(lock,flags)
...
临界区//不要有可能引起阻塞的代码copy_from_user,copy_to_user,kmalloc,msleep
...
spin_lock_irqrestore(lock,flags)

三 读写自旋锁

只有读与读可以并发,读写不能并发,写与写不能并发。与自旋锁比较,区分临界区的读写操作。

读操作
read_lock(lock)-->read_unlock
read_lock_irqsave-->read)unlock_irqrestore

写操作
write_lock--->write_unlock
write_lock_irqsave-->write_lock_irqrestore

四 顺序自旋锁

只有写与写是互斥的,读与写不互斥,读操作期间可能发生了写操作,故需判断是否发生了写操作,有则重读。

写执行单元

write_seqlock-->write_sequnlock
write_seqtrylock-->
write_seqlock_irqsave-->
write_seqlock_irq-->
write_seqlock_bh-->

读执行单元
unsigned read_seqbegin(seqlock)返回一个顺序号
读完需判断是否需要重读
read_seqretry(lock, seqnum)
读操作用法:
do {
   seqnum = read_seqbegin(lock);
   ...
} while (read_seqretry(lock, seqnum));

五 互斥体

mutex_lock与spin_lock相比,mutex_lock没获得锁会睡眠,发生进程上下文切换。进程上下文切换开销大,所以互斥体一般用于进程占用资源时间较长时。互斥体是进程级的,一般不能用于中断(因为会睡眠),一定要用可以用mutex_trylock,获取不到避免阻塞,中断可以用自旋锁。

struct mutex my_mutex;
mutex_init(&my_mutex);

mutex_lock(&my_mutex);//获取不到,睡眠,不可被信号打断
...
mutex_unlock(&my_mutex);

mutex_lock_interruptible(&my_mutex)//获取不到,睡眠,可被信号打断

mutex_trylock(&ny_mutex)//尝试获取,获取不到不会睡眠。


linux kernel 信号量、互斥锁、自旋锁

1.信号量1.1 概念信号量又称为信号灯(semaphore),本质上信号量是一个计数器,它用来记录对某个资源(如共享内存)的存取状况。一般说来,为了获得共享资源,进程需要执行下列操作:    (...
  • u012719256
  • u012719256
  • 2016-09-26 14:42:52
  • 2403

[Linux]互斥机制(中断屏蔽、原子操作、自旋锁、信号量)

基本概念 临界区 互斥机制 用户空间和内核空间 互斥机制 中断屏蔽、原子操作、自旋锁、信号量...
  • dearsq
  • dearsq
  • 2016-08-10 19:16:30
  • 1677

互斥体、原子操作、自旋锁、信号量

一、互斥体 struct mutex my_mutex;//定义mutex mutex_init(&my_mutex);//初始化mutex mutex_lock(&my_mutex);...
  • lindonghai
  • lindonghai
  • 2013-06-14 17:37:17
  • 1004

信号量、互斥体和自旋锁小结

信号量、互斥体和自旋锁小结
  • XSF50717
  • XSF50717
  • 2015-08-04 23:43:37
  • 1257

Linux 内核同步之自旋锁与信号量的异同

Linux 设备驱动中必须解决的一个问题是多个进程对共享资源的并发访问,并发访问会导致竞态,linux 提供了多种解决竞态问题的方式,这些方式适合不同的应用场景。   Linux 内核是多进程、多...
  • liuxd3000
  • liuxd3000
  • 2013-02-03 16:10:43
  • 2036

Linux 内核中的并发--信号量与互斥体

信号量(down操作->临界区->up操作) 信号量的使用方式和自旋锁类似,进程只有得到信号量才能执行临界区代码 但与自旋锁不同的是,当进程获取不到信号量时并不是原地打转而是睡眠等待 中断服...
  • xyfabcde
  • xyfabcde
  • 2017-06-01 18:16:53
  • 531

原子操作 信号量 自旋锁 互斥锁

原子操作 信号量 自旋锁 互斥锁
  • xiaofeige567
  • xiaofeige567
  • 2014-10-20 22:36:16
  • 1143

内核下各种同步处理方法(自旋锁、信号灯、互斥体…)

转自:http://www.blogfshare.com/kernel-synchronization.html 1.在支持多线程的操作系统下,有些函数会出现不可重入的现象。所谓“可重入”是指函数...
  • lixiangminghate
  • lixiangminghate
  • 2017-02-08 10:11:38
  • 349

自旋锁和互斥体

2.5 内核中的并发   随着多核笔记本电脑时代的到来,对称多处理器(SMP)的使用不再被限于高科技用户。SMP和内核抢占是多线程执行的两种场景。多个线程能够同时操作共享的内核数据结构,因此,对...
  • xpy123
  • xpy123
  • 2015-06-15 11:50:00
  • 332

自旋锁互斥体

Linux中与自旋锁相关的操作主要有以下4种。1.定义自旋锁spinlock_t lock;2.初始化自旋锁spin_lock_init(lock)该宏用于动态初始化自旋锁lock。3.获得自旋锁sp...
  • csdn1126274345
  • csdn1126274345
  • 2018-03-21 21:30:02
  • 9
收藏助手
不良信息举报
您举报文章:linux内核并发控制-互斥体、自旋锁、中断屏蔽
举报原因:
原因补充:

(最多只允许输入30个字)