自旋锁,互斥锁,信号量

来源:互联网 发布:中国复杂网络大会 编辑:程序博客网 时间:2024/04/26 16:06

自旋锁,互斥锁,信号量

乐观锁和悲观锁只是一种理论,是从思想上划分的。自旋锁和互斥锁是应用层确确实实的锁,用于同步访问控制,如果一定要划分,从只有一个线程可以拥有锁来说,我觉得自旋锁和互斥锁应该都属于悲观锁,因为一般的应用不需要支持事物回滚的操作。但是沈询的直播中说,互斥锁属于悲观锁(sleep),自旋锁属于乐观锁(轮询)。因此可能乐观锁,悲观锁早就不是数据库级的那种老定义了。

      POSIX threads(简称Pthreads)是在多核平台上进行并行编程的一套常用的API。线程同步(Thread Synchronization)是并行编程中非常重要的通讯手段,其中最典型的应用就是用Pthreads提供的锁机制(lock)来对多个线程之间共 享的临界区(Critical Section)进行保护(另一种常用的同步机制是barrier)

Pthreads提供了多种锁机制:
(1) Mutex(互斥量):pthread_mutex_***
(2) Spin lock(自旋锁):pthread_spin_***
(3) Condition Variable(条件变量):pthread_con_***
(4) Read/Write lock(读写锁):pthread_rwlock_***

Pthreads提供的Mutex锁操作相关的API主要有:
pthread_mutex_lock (pthread_mutex_t *mutex);
pthread_mutex_trylock (pthread_mutex_t *mutex);
pthread_mutex_unlock (pthread_mutex_t *mutex);

Pthreads提供的与Spin Lock锁操作相关的API主要有:
pthread_spin_lock (pthread_spinlock_t *lock);
pthread_spin_trylock (pthread_spinlock_t *lock);
pthread_spin_unlock (pthread_spinlock_t *lock);

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

    Spin lock则不然,它属于busy-waiting类型的锁,如果线程A是使用pthread_spin_lock操作去请求锁,那么线程A就会一直在Core0上进行忙等待并不停的进行锁请求,直到得到这个锁为止。

 

   所以,自旋锁一般用多核的服务器(需要一直占用CPU资源),临界区持有时间比较短的竞争(占用CPU的时间不会太长,避免线程切换,就可以拥有锁),读大于写的场景。

 

信号量、互斥锁和自旋锁的区别

    信号量互斥锁允许进程sleep属于睡眠锁,自旋锁不允许调用者sleep,而是让其循环等待,所以有以下区别应用:

Ø 信号量和读写信号量适合于保持时间较长的情况,它们会导致调用者睡眠,因而自旋锁适合于保持时间非常短的情况;

Ø 自旋锁可以用于中断,不能用于进程上下文(会引起死锁),而信号量不允许使用在中断中,而可以用于进程上下文;

Ø 自旋锁保持期间是抢占失效的,自旋锁被持有时,内核不能被抢占,而信号量和读写信号量保持期间是可以被抢占的。

另外需要注意的是:

Ø 信号量锁保护的临界区可包含可能引起阻塞的代码,而自旋锁则绝对要避免用来保护包含这样代码的临界区,因为阻塞意味着要进行进程的切换,如果进程被切换出去后,另一进程企图获取本自旋锁,死锁就会发生;

Ø 占用信号量的同时不能占用自旋锁,因为在等待信号量时可能会睡眠,而在持有自旋锁时是不允许睡眠的。

Ø 信号量主要适用于进程间通信,当然,也可用于线程间通信。而互斥锁,自旋锁只能用于线程间通信。

0 0
原创粉丝点击