Chinaunix首页 | 论坛 | 博客
  • 博客访问: 716098
  • 博文数量: 67
  • 博客积分: 994
  • 博客等级: 准尉
  • 技术积分: 1749
  • 用 户 组: 普通用户
  • 注册时间: 2011-08-03 14:10
文章分类
文章存档

2014年(11)

2013年(14)

2012年(14)

2011年(28)

分类: LINUX

2011-11-25 21:28:49

锁大家接触的应该很早吧,家里经常使用锁来锁门。这里主要讲一下自旋锁。也许你会问,各种锁之间有什么区别?他们的主要区别是在申请锁失败后的表现形式,有的会不停的进行检查锁是否释放,而有的则去睡觉。我们下来讲到的自旋锁就属于前一种表现。

自旋锁的引入:自旋锁是专为防止多处理器并发而引入的一种锁,它在内核中大量用于中断处理等。对于单处理器我们可以使用关中断来防止中断处理程序的并发执行。且自旋锁只能用于短时间的锁定,用于中断上下文。为什么不可以长时间拥有?前面已经说了,自旋锁在等待锁重新可用期间是在自旋,这对处理器来说是非常浪费时间且效率低下的。

自旋锁定义如下:

比较旧的内核:

typedef struct {

volatile unsigned int lock;

}spinlock_t;

3.0.4内核定义:

64 typedef struct spinlock {

65 union {

66 struct raw_spinlock rlock;

67

68 #ifdef CONFIG_DEBUG_LOCK_ALLOC

69 # define LOCK_PADSIZE (offsetof(struct raw_spinlock, dep_map))

70 struct {

71 u8 __padding[LOCK_PADSIZE];

72 struct lockdep_map dep_map;

73 };

74 #endif

75 };

76 } spinlock_t;

在新版源码里自旋锁共用了一段共享空间,里面定义了两个结构体, struct raw_spinlock的具体定义如下:

20 typedef struct raw_spinlock {

21 arch_spinlock_t raw_lock;

22 #ifdef CONFIG_GENERIC_LOCKBREAK

23 unsigned int break_lock;

24 #endif

25 #ifdef CONFIG_DEBUG_SPINLOCK

26 unsigned int magic, owner_cpu;

27 void *owner;

28 #endif

29 #ifdef CONFIG_DEBUG_LOCK_ALLOC

30 struct lockdep_map dep_map;

31 #endif

32 } raw_spinlock_t;

里面定义了一系列的锁。上面的 raw_spinlock_t类型其实就是 spinlock_t类型。

自旋锁的的基本使用如下:

DEFINE_SPINLOCK(x)

spin_lock(x);

/临界区*********/

spin_unlock(x);

自旋锁的初始化函数spin_lock_init(_lock) ,自旋锁的加锁和解锁函数定义如下:

283 static inline void spin_lock(spinlock_t *lock)

284 {

285 raw_spin_lock(&lock->rlock);

286 }

323 static inline void spin_unlock(spinlock_t *lock)

324 {

325 raw_spin_unlock(&lock->rlock);

326 }

由于在内核中大量地使用了spinlock,有大量的临界区存在,因此它们将严重地影响着系统的实时性。 (自旋) 因此以后使用互斥体(mutex)来代替自旋锁。

Spinlock失效抢占的目的是避免死锁。Spinlock如果可抢占了,一个spinlock的竞争者将可能抢占该spinlock的保持者来 运行,但是由于得不到spinlock将自旋在那里,如果竞争者的优先级高于保持者的优先级,将形成一种死锁的局面,因为保持者无法得到运行而永远不能释 放spinlock,而竞争者由于不能得到一个不可能释放的spinlock而永远自旋在那里。

由于中断处理函数也可以使用spinlock,如果它使用的spinlock已经被一个进程保持,中断处理函数将无法继续进行,从而形成死锁,这样 的spinlock在使用时应当中断失效来避免这种死锁的情况发生。标准linux内核就是这么做的,中断线程化之后,中断失效就没有必要,因为遇到这种 状况后,中断线程将挂在等待队列上并放弃CPU让别的线程或进程来运行。

等待队列就是解决这种死锁僵局的方法,每个spinlock都有一个等待队列,该等待队列是按进程或线程的优先级排队的。如果一个进程或线程竞争的spinlock 已经被另一个线程保持,它将把自己挂在该spinlock的优先级化的等待队列上,然后发生调度把CPU让给别的进程或线程。

阅读(2308) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~