内核同步方法之读写自旋锁

 

   当对某个数据结构的操作可以像这样被划分为读/写两种类别时,类似读/写锁这样的机制就很有用了。Linux的读写自旋锁为读和写分别提供了不同的锁,一个或多个读任务可以并发的持有读者锁;用于写的锁最多只能被一个写任务持有,而且此时不能有并发的读操作。有时候读写锁叫做共享排斥锁,或者并发排斥锁,因为这种锁以共享(对读者而言)和排斥(对写着而言)的形式获得使用。

  1. /*
  2.  * Read-write spinlocks, allowing multiple readers
  3.  * but only one writer.
  4. */
  1. typedef struct {
  2.     raw_rwlock_t raw_lock;
  3. #if defined(CONFIG_PREEMPT) && defined(CONFIG_SMP)
  4.     unsigned int break_lock;
  5. #endif
  6. #ifdef CONFIG_DEBUG_SPINLOCK
  7.     unsigned int magic, owner_cpu;
  8.     void *owner;
  9. #endif
  10. #ifdef CONFIG_DEBUG_LOCK_ALLOC
  11.     struct lockdep_map dep_map;
  12. #endif
  13. } rwlock_t;

 

  1. #define write_lock(lock)        _write_lock(lock)
  2. #define read_lock(lock)         _read_lock(lock)
  3. #define _read_lock(lock)            __LOCK(lock)
  4. #define _write_lock(lock)           __LOCK(lock)
  5. void __lockfunc _write_lock(rwlock_t *lock)
  6. {
  7.     preempt_disable();
  8.     rwlock_acquire(lock->dep_map, 0, 0, _RET_IP_);
  9.     _raw_write_lock(lock);
  10. }

通常情况下,读锁和写锁会位于完全分割开的代码分支中。注意,不能把一个读锁“升级”为写锁。如下代码:

  1. rwlock_t mr_rwlock = RW_LOCK_UNLOCK; 
  2. read_lock(&mr_rwlock);
  3. write_lock(&mr_rwlock);

将会带来死锁。因为写锁会不断的自旋,等待所有的读者释放锁,其中也包括它自己。所以当确实需要写操作时,要一开始就请求写锁。如果写和读不能清晰地分开的话,那么使用一般的自旋锁就行了,不要使用读写自旋锁。

   多个读者可以安全地获得同一个读锁,即使一个线程递归的获得同一个读锁也是安全的,这个特性是读写自旋锁真正成为一种有用并且常用的优化手段。如果中断处理程序中只有读操作而没有写操作,那么就可以混合使用“中断禁止”锁,使用read_lock()而不是read_lock_irqsave()对读进行保护。不过,还是需要write_lock_irqsave()禁止所有写操作的中断,否则,中断里的读操作就有可能锁死在写锁上。

 

读写自旋锁的方法:

 

  1. #ifdef CONFIG_DEBUG_SPINLOCK
  2.   extern void __spin_lock_init(spinlock_t *lock, const char *name,
  3.                    struct lock_class_key *key);
  4. # define spin_lock_init(lock)                   /
  5. do {                                /
  6.     static struct lock_class_key __key;         /
  7.                                 /
  8.     __spin_lock_init((lock), #lock, &__key);        /
  9. while (0)
  10. #else
  11. # define spin_lock_init(lock)                   /
  12.     do { *(lock) = SPIN_LOCK_UNLOCKED; } while (0)
  13. #endif
  14. #ifdef CONFIG_DEBUG_SPINLOCK
  15.   extern void __rwlock_init(rwlock_t *lock, const char *name,
  16.                 struct lock_class_key *key);
  17. # define rwlock_init(lock)                  /
  18. do {                                /
  19.     static struct lock_class_key __key;         /
  20.                                 /
  21.     __rwlock_init((lock), #lock, &__key);           /
  22. while (0)
  23. #else
  24. # define rwlock_init(lock)                  /
  25.     do { *(lock) = RW_LOCK_UNLOCKED; } while (0)
  26. #endif
  27. #define spin_is_locked(lock)    __raw_spin_is_locked(&(lock)->raw_lock)
  28. /**
  29.  * spin_unlock_wait - wait until the spinlock gets unlocked
  30.  * @lock: the spinlock in question.
  31.  */
  32. #define spin_unlock_wait(lock)  __raw_spin_unlock_wait(&(lock)->raw_lock)
  33. #define read_trylock(lock)      __cond_lock(lock, _read_trylock(lock))
  34. #define write_trylock(lock)     __cond_lock(lock, _write_trylock(lock))
  35. #if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)
  36. #define read_lock_irqsave(lock, flags)  flags = _read_lock_irqsave(lock)
  37. #define write_lock_irqsave(lock, flags) flags = _write_lock_irqsave(lock)
  38. #else
  39. #define read_lock_irqsave(lock, flags)  _read_lock_irqsave(lock, flags)
  40. #define write_lock_irqsave(lock, flags) _write_lock_irqsave(lock, flags)
  41. #endif
  42. #define read_lock_irq(lock)     _read_lock_irq(lock)
  43. #define read_lock_bh(lock)      _read_lock_bh(lock)
  44. #define write_lock_irq(lock)        _write_lock_irq(lock)
  45. #define write_lock_bh(lock)     _write_lock_bh(lock)
  46. #define read_lock_irq(lock)     _read_lock_irq(lock)
  47. #define read_lock_bh(lock)      _read_lock_bh(lock)
  48. #define write_lock_irq(lock)        _write_lock_irq(lock)
  49. #define write_lock_bh(lock)     _write_lock_bh(lock)
  50. /*
  51.  * We inline the unlock functions in the nondebug case:
  52.  */
  53. #if defined(CONFIG_DEBUG_SPINLOCK) || defined(CONFIG_PREEMPT) || /
  54.     !defined(CONFIG_SMP)
  55. # define read_unlock(lock)      _read_unlock(lock)
  56. # define write_unlock(lock)     _write_unlock(lock)
  57. # define spin_unlock_irq(lock)      _spin_unlock_irq(lock)
  58. # define read_unlock_irq(lock)      _read_unlock_irq(lock)
  59. # define write_unlock_irq(lock)     _write_unlock_irq(lock)
  60. #else
  61. # define read_unlock(lock) /
  62.     do {__raw_read_unlock(&(lock)->raw_lock); __release(lock); } while (0)
  63. # define write_unlock(lock) /
  64.     do {__raw_write_unlock(&(lock)->raw_lock); __release(lock); } while (0)
  65. # define spin_unlock_irq(lock)          /
  66. do {                        /
  67.     __raw_spin_unlock(&(lock)->raw_lock);   /
  68.     __release(lock);            /
  69.     local_irq_enable();         /
  70. while (0)
  71. # define read_unlock_irq(lock)          /
  72. do {                        /
  73.     __raw_read_unlock(&(lock)->raw_lock);   /
  74.     __release(lock);            /
  75.     local_irq_enable();         /
  76. while (0)
  77. # define write_unlock_irq(lock)         /
  78. do {                        /
  79.     __raw_write_unlock(&(lock)->raw_lock);  /
  80.     __release(lock);            /
  81.     local_irq_enable();         /
  82. while (0)
  83. #endif
  84. #define spin_unlock_irqrestore(lock, flags) /
  85.                     _spin_unlock_irqrestore(lock, flags)
  86. #define spin_unlock_bh(lock)        _spin_unlock_bh(lock)
  87. #define read_unlock_irqrestore(lock, flags) /
  88.                     _read_unlock_irqrestore(lock, flags)
  89. #define read_unlock_bh(lock)        _read_unlock_bh(lock)
  90. #define write_unlock_irqrestore(lock, flags) /
  91.                     _write_unlock_irqrestore(lock, flags)
  92. #define write_unlock_bh(lock)       _write_unlock_bh(lock)

  在使用Linux读写自旋锁时,最后要考虑的一点是这种机制照顾读比照顾写多。当读锁被持有时,写操作为了互斥访问而只能等待;但是,读者却可以继续成功地占用锁。自旋等待的写者在所有读者释放锁之前是无法获得锁的。

  如果加锁时间不长且代码不会睡眠(比如中断处理程序),利用自旋锁是最佳选择。

你可能感兴趣的:(Linux内核设计与实现)