Linux内核同步机制之信号量与锁

Linux内核同步控制方法有很多,信号量、锁、原子量、RCU等等,不同的实现方法应用于不同的环境来提高操作系统效率。首先,看看我们最熟悉的两种机制——信号量、锁。

一、信号量 

首先还是看看内核中是怎么实现的,内核中用struct semaphore数据结构表示信号量(<linux/semphone.h>中):

  1. struct semaphore {  
  2.     spinlock_t      lock;  
  3.     unsigned int        count;  
  4.     struct list_head    wait_list;  
  5. };  

其中lock为自旋锁,放到这里是为了保护count的原子增减,无符号数count为我们竞争的信号量(PV操作的核心),wait_list为等待此信号量的进程链表。

初始化:

对于这一类工具类使用较多的机制,包括用于同步互斥的信号量、锁、completion,用于进程等待的等待队列、用于Per-CPU的变量等等,内核都提供了两种初始化方法,静态与动态方式。 

1)      静态初始化,实现代码如下:

  1. #define __SEMAPHORE_INITIALIZER(name, n)                \   
  2. {                                   \  
  3.     .lock       = __SPIN_LOCK_UNLOCKED((name).lock),        \  
  4.     .count      = n,                        \  
  5.     .wait_list  = LIST_HEAD_INIT((name).wait_list),     \  
  6. }  
  7.   
  8. #define DECLARE_MUTEX(name) \   
  9.     struct semaphore name = __SEMAPHORE_INITIALIZER(name, 1)  

可以看到,这种初始化使我们在编程的时候直接用一条语句DECLARE_MUTEX(name);就可以完成申明与初始化,另一种下面要说的动态初始化方式申请与初始化分离。

2)      我们看到,静态初始化时信号量的count值初始化为1,当我们需要初始化为0时需要用动态初始化方法。

  1. #define init_MUTEX(sem)     sema_init(sem, 1)   
  2. #define init_MUTEX_LOCKED(sem)  sema_init(sem, 0)   
  3.   
  4. static inline void sema_init(struct semaphore *sem, int val)  
  5. {  
  6.     static struct lock_class_key __key;  
  7.     *sem = (struct semaphore) __SEMAPHORE_INITIALIZER(*sem, val);  
  8.     lockdep_init_map(&sem->lock.dep_map, "semaphore->lock", &__key, 0);  
  9. }  

相关推荐