第7章 Linux并发控制-互斥锁

7.7 互斥锁

信号量可以实现互斥的功能,但是mutex在Linux内核中还是真实地存在着。

定义名为mutex的互斥锁并初始化:

struct mutex mutex;

mutex_init(&mutex);

下面的函数用于获取互斥锁:

void mutex_lock(struct mutex *lock);
int mutex_lock_interruptible(struct mutex *lock);

int mutex_trylock(struct mutex *lock);

mutex_lock()与mutex_lock_interruptible()的区别,mutex_lock()引起的睡眠不能被信号打断,而mutex_lock_interruptible()可以。mutex_trylock()用于尝试获得mutex,获取不到mutex时不会引起进程睡眠。

下列函数用于释放互斥锁:

void mutex_unlock(struct mutex *lock);

mutex的使用方法和信号量用于互斥的场合完全一样:

struct mutex my_mutex;      /* 定义mutex */
mutex_init(&my_mutex);      /* 初始化mutex */
mutex_lock(&my_mutex);      /* 获取mutex */
...     /* 临界资源*/

mutex_unlock(&my_mutex);    /* 释放mutex */

自旋锁和互斥锁都是解决互斥问题的基本手段,面对特定的情况,应该如何取舍这两种手段呢?选择的依据是临界区的性质和系统的特点

从严格意义上说,互斥锁和自旋锁属于不同层次的互斥手段,互斥锁的实现依赖于自旋锁。在互斥锁本身的实现上,为了保证互斥锁结构存取的原子性,需要自旋锁来互斥。所以自旋锁属于更底层的手段。

互斥锁是进程级的,用于多个进程之间对资源的互斥,虽然也是在内核中,但是该内核执行路径是以进程的身份,代表进程来争夺资源的。如果竞争失败,会发生进程上下文切换,当前进程进入睡眠状态,CPU将运行其他进程。鉴于进程上下文切换的开销也很大,因此,只有当进程占用资源时间较长时,用互斥锁才是较好的选择

当要保护的临界区访问时间比较短时,使用自旋锁,因为自旋锁可节省上下文切换的时间。但CPU得不到自旋锁会在那里空转直到其他执行单元解锁为止,所以要求锁不能在临界区里长时间停留,否则会降低系统的效率。

总结:自旋锁和互斥锁选用的3项原则。

1)当锁不能被获取到时,使用互斥锁的开销是进程上下文切换时间,使用自旋锁的开销是等待获取自旋锁(由临界区执行时间决定)。若临界区比较小,宜使用自旋锁,若临界区很大,应使用互斥锁。

2)互斥锁所保护的临界区可包含可能引起阻塞的代码,而自旋锁所保护的临界区绝对不可以包含可能引起阻塞代码。因为阻塞要进行进程的切换,如果进程被切换出去后,另一个进程企图获取本自旋锁,就会发生死锁。

3)互斥锁存在于进程上下文,因此,如果被保护的共享资源需要在中断或软中断情况下使用,则在互斥锁和自旋锁之间只能选择自旋锁。如果一定要使用互斥锁,则只能通过mutex_trylock()方式进行,不能获取就立即返回以避免阻塞。


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值