技术开发 频道

Linux驱动开发必看:详解神秘内核

  2.5.1 自旋锁和互斥体

  访问共享资源的代码区域称作临界区。自旋锁(spinlock)和互斥体(mutex,mutual exclusion的缩写)是保护内核临界区的两种基本机制。我们逐个分析。

  自旋锁可以确保在同时只有一个线程进入临界区。其他想进入临界区的线程必须不停地原地打转,直到第1个线程释放自旋锁。注意:这里所说的线程不是内核线程,而是执行的线程。

  下面的例子演示了自旋锁的基本用法:

#include <linux/spinlock.h>
spinlock_t mylock
= SPIN_LOCK_UNLOCKED; /* Initialize */

/* Acquire the spinlock. This is inexpensive if there
* is no one inside the critical section. In the face of
* contention, spinlock() has to busy-wait.
*/
spin_lock(
&mylock);

/* ... Critical Section code ... */

spin_unlock(
&mylock); /* Release the lock */

  与自旋锁不同的是,互斥体在进入一个被占用的临界区之前不会原地打转,而是使当前线程进入睡眠状态。如果要等待的时间较长,互斥体比自旋锁更合适,因为自旋锁会消耗CPU资源。在使用互斥体的场合,多于2次进程切换时间都可被认为是长时间,因此一个互斥体会引起本线程睡眠,而当其被唤醒时,它需要被切换回来。

  因此,在很多情况下,决定使用自旋锁还是互斥体相对来说很容易:

  (1) 如果临界区需要睡眠,只能使用互斥体,因为在获得自旋锁后进行调度、抢占以及在等待队列上睡眠都是非法的;

  (2) 由于互斥体会在面临竞争的情况下将当前线程置于睡眠状态,因此,在中断处理函数中,只能使用自旋锁。(第4章将介绍更多的关于中断上下文的限制。)

  下面的例子演示了互斥体使用的基本方法:

#include <linux/mutex.h>

/* Statically declare a mutex. To dynamically
   create a mutex, use mutex_init()
*/
static DEFINE_MUTEX(mymutex);

/* Acquire the mutex. This is inexpensive if there
* is no one inside the critical section. In the face of
* contention, mutex_lock() puts the calling thread to sleep.
*/
mutex_lock(
&mymutex);

/* ... Critical Section code ... */

mutex_unlock(
&mymutex);      /* Release the mutex */

  为了论证并发保护的用法,我们首先从一个仅存在于进程上下文的临界区开始,并以下面的顺序逐步增加复杂性:

  (1) 非抢占内核,单CPU情况下存在于进程上下文的临界区;

  (2) 非抢占内核,单CPU情况下存在于进程和中断上下文的临界区;

  (3) 可抢占内核,单CPU情况下存在于进程和中断上下文的临界区;

  (4) 可抢占内核,SMP情况下存在于进程和中断上下文的临界区。

0
相关文章