自旋鎖是用于保護(hù)短的代碼片段,其中只包含少量C語句,因此會很快執(zhí)行完畢。大多數(shù)內(nèi)核數(shù)據(jù)結(jié)構(gòu)都有自身的自旋鎖,在處理結(jié)構(gòu)中的關(guān)鍵成員時,必須獲得相應(yīng)的自旋鎖。
定義自旋鎖
struct task_struct {
...
/* Protection of (de-)allocation: mm, files, fs, tty, keyrings */
spinlock_t alloc_lock;
...
1757 /*
1758 * Protects ->fs, ->files, ->mm, ->group_info, ->comm, keyring
1759 * subscriptions and synchronises with wait4(). Also used in procfs. Also
1760 * pins the final release of task.io_context. Also protects ->cpuset and
1761 * ->cgroup.subsys[].
1762 *
1763 * Nests both inside and outside of read_lock(&tasklist_lock).
1764 * It must not be nested with write_lock_irq(&tasklist_lock),
1765 * neither inside nor outside.
1766 */
初始化自旋鎖
./kernel/fork.c:1049: spin_lock_init(&p->alloc_lock);
獲取自旋鎖
1767 static inline void task_lock(struct task_struct *p)
1768 {
1769 spin_lock(&p->alloc_lock);
1770 }
釋放自旋鎖
1772 static inline void task_unlock(struct task_struct *p)
1773 {
1774 spin_unlock(&p->alloc_lock);
1775 }
自旋鎖的使用
在處理 task_struct 結(jié)構(gòu)中的 ptrace / files / active_mm / mm / flags / cgroups / io_context 等關(guān)鍵成員時,需要獲取 alloc_lock 自旋鎖。
void foo()
{
task_lock(current);
// 處理 task_struct 結(jié)構(gòu)的關(guān)鍵成員
task_unlock(current);
}
為什么這么多關(guān)鍵成員都使用同一個 alloc_lock 自旋鎖呢? 不會影響性能嗎? 為什么不使用不同的自旋鎖呢?
個人理解:因為使用 alloc_lock 所保護(hù)的關(guān)鍵成員操作并不頻繁,而且操作的時間點(diǎn)并不集中,所以不會影響性能。
自旋鎖用來在多處理器的環(huán)境下保護(hù)數(shù)據(jù)。如果內(nèi)核發(fā)現(xiàn)數(shù)據(jù)未鎖,就獲取鎖并運(yùn)行;如果數(shù)據(jù)已鎖,就一直旋轉(zhuǎn),其實是一直反復(fù)執(zhí)行一條指令。之所以說自旋鎖用在多處理器環(huán)境,是因為在單處理器環(huán)境(非搶占式內(nèi)核)下,自旋鎖其實不起作用。在單處理器搶占式內(nèi)核的情況下,自旋鎖起到禁止搶占的作用。
因為被自旋鎖鎖著的進(jìn)程一直旋轉(zhuǎn),而不是睡眠,所以自旋鎖可以用在中斷等禁止睡眠的場景。
spin_lock 會考慮下面兩種情況:
- 如果內(nèi)核中其他地方尚未獲得 lock,則有當(dāng)前處理器獲取。其它處理器不能再進(jìn)入 lock 保護(hù)的代碼范圍。
- 如果 lock 已經(jīng)由另一個處理器獲得,spin_lock 進(jìn)入一個無限循環(huán),重復(fù)地檢查 lock 是否已經(jīng)由 spin_unlock 釋放(自旋鎖因此得名)。如果已經(jīng)釋放,則獲得 lock ,并進(jìn)入臨界區(qū)。
在使用自旋鎖時必須要注意下面兩點(diǎn)。
- 如果獲得鎖之后不釋放,系統(tǒng)將變的不可用。所有的處理器(包括獲得鎖的在內(nèi)),遲早需要進(jìn)入對應(yīng)的臨界區(qū)。它們會進(jìn)入無限循環(huán)等待鎖釋放,但等不到。便產(chǎn)生了死鎖。
- 自旋鎖絕不應(yīng)該長期持有,因為所有等待釋放鎖的處理器都處于不可用狀態(tài),無法用于其他工作(信號量的情形有所不同)。