Linux內核同步控制方法有很多,信號量、鎖、原子量、RCU等等,不同的實現方法應用於不同的環境來提高操作系統效率。首先,看看我們最熟悉的兩種機制——信號量、鎖。
一、信號量
首先還是看看內核中是怎麼實現的,內核中用struct semaphore數據結構表示信號量(<linux/semphone.h>中):
- struct semaphore {
- spinlock_t lock;
- unsigned int count;
- struct list_head wait_list;
- };
其中lock為自旋鎖,放到這裡是為了保護count的原子增減,無符號數count為我們競爭的信號量(PV操作的核心),wait_list為等待此信號量的進程鏈表。
初始化:
對於這一類工具類使用較多的機制,包括用於同步互斥的信號量、鎖、completion,用於進程等待的等待隊列、用於Per-CPU的變量等等,內核都提供了兩種初始化方法,靜態與動態方式。
1) 靜態初始化,實現代碼如下:
- #define __SEMAPHORE_INITIALIZER(name, n) \
- { \
- .lock = __SPIN_LOCK_UNLOCKED((name).lock), \
- .count = n, \
- .wait_list = LIST_HEAD_INIT((name).wait_list), \
- }
-
- #define DECLARE_MUTEX(name) \
- struct semaphore name = __SEMAPHORE_INITIALIZER(name, 1)
可以看到,這種初始化使我們在編程的時候直接用一條語句DECLARE_MUTEX(name);就可以完成申明與初始化,另一種下面要說的動態初始化方式申請與初始化分離。
2) 我們看到,靜態初始化時信號量的count值初始化為1,當我們需要初始化為0時需要用動態初始化方法。
- #define init_MUTEX(sem) sema_init(sem, 1)
- #define init_MUTEX_LOCKED(sem) sema_init(sem, 0)
-
- static inline void sema_init(struct semaphore *sem, int val)
- {
- static struct lock_class_key __key;
- *sem = (struct semaphore) __SEMAPHORE_INITIALIZER(*sem, val);
- lockdep_init_map(&sem->lock.dep_map, "semaphore->lock", &__key, 0);
- }