(2) 4.19版本開(kāi)始支持傷害-等待(Wound-Wait)算法:一個(gè)事務(wù)申請(qǐng)另一個(gè)事務(wù)已經(jīng)獲取的鎖的時(shí)候,如果持有鎖的事務(wù)年輕,那么申請(qǐng)鎖的事務(wù)傷害(wound)持有鎖的事務(wù),請(qǐng)求它去死亡;如果持有鎖的事務(wù)年老,那么申請(qǐng)鎖的事務(wù)等待(wait)。
假設(shè)進(jìn)程1和進(jìn)程2分別在2個(gè)處理器上運(yùn)行,進(jìn)程1獲取鎖A,進(jìn)程2獲取鎖B,然后進(jìn)程1申請(qǐng)鎖B,進(jìn)程2申請(qǐng)鎖A。假設(shè)進(jìn)程1的門(mén)票編號(hào)比進(jìn)程2的門(mén)票編號(hào)小,也就是進(jìn)程1年老,進(jìn)程2年輕。假設(shè)選擇等待-死亡算法。年老的進(jìn)程1申請(qǐng)鎖B,發(fā)現(xiàn)持有鎖B的進(jìn)程2年輕,那么年老的進(jìn)程1等待。年輕的進(jìn)程2申請(qǐng)鎖A,發(fā)現(xiàn)持有鎖A的進(jìn)程1年老,那么年輕的進(jìn)程2死亡(即申請(qǐng)鎖的函數(shù)返回“-EDEADLK”),接著回滾(即釋放已經(jīng)獲取的鎖B),然后重新開(kāi)始:先申請(qǐng)鎖A然后申請(qǐng)鎖B(必須改變申請(qǐng)順序,如果先申請(qǐng)鎖B,那么會(huì)把剛釋放的鎖B搶回來(lái))。假設(shè)選擇傷害-等待算法。年老的進(jìn)程1申請(qǐng)鎖B,發(fā)現(xiàn)持有鎖B的進(jìn)程2年輕,那么傷害年輕的進(jìn)程2,請(qǐng)求它死亡。年輕的進(jìn)程2申請(qǐng)鎖A,發(fā)現(xiàn)持有鎖A的進(jìn)程1年老,那么年輕的進(jìn)程2等待,在收到進(jìn)程1的死亡請(qǐng)求以后,年輕的進(jìn)程2死亡(即申請(qǐng)鎖的函數(shù)返回“-EDEADLK”),接著回滾(即釋放已經(jīng)獲取的鎖B),然后重新開(kāi)始:先申請(qǐng)鎖A然后申請(qǐng)鎖B。兩種算法都是公平的,因?yàn)槠渲幸粋€(gè)事務(wù)最終會(huì)成功。和等待-死亡算法相比,傷害-等待算法生成的退避少,但是從一次退避恢復(fù)的時(shí)候要做更多的工作。傷害-等待算法是一種搶占性的算法(因?yàn)槭聞?wù)被其它事務(wù)傷害),需要一種可靠的方法來(lái)選擇受傷狀態(tài)和搶占正在運(yùn)行的事務(wù)。在傷害-等待算法中,一個(gè)事務(wù)在受傷后死亡(返回“-EDEADLK”),就認(rèn)為這個(gè)事務(wù)被搶占。如果競(jìng)爭(zhēng)鎖的進(jìn)程少,并且希望減少回滾的次數(shù),那么應(yīng)該選擇傷害-等待算法。 和普通的互斥鎖相比,傷害/等待互斥鎖增加了下面2個(gè)概念。(1)獲取上下文(acquire context):一個(gè)獲取上下文表示一個(gè)事務(wù),關(guān)聯(lián)一張門(mén)票(ticket),門(mén)票也稱為序列號(hào),門(mén)票編號(hào)小表示年老,門(mén)票編號(hào)大表示年輕。獲取上下文跟蹤調(diào)試狀態(tài),捕獲對(duì)傷害/等待互斥鎖接口的錯(cuò)誤使用。
(2)傷害/等待類:初始化獲取上下文的時(shí)候需要指定鎖類,鎖類會(huì)給獲取上下文分配門(mén)票。鎖類也指定算法:等待-死亡(Wait-Die)或傷害-等待(Wound-Wait)。當(dāng)多個(gè)進(jìn)程競(jìng)爭(zhēng)同一個(gè)鎖集合的時(shí)候,它們必須使用相同的鎖類。
有3種獲取傷害/等待互斥鎖的函數(shù),如下。(1) 普通的獲取鎖函數(shù)ww_mutex_lock(),帶有獲取上下文。
(2) 進(jìn)程在回滾(即釋放所有已經(jīng)獲取的鎖)以后,使用慢路徑獲取鎖函數(shù)ww_mutex_lock_slow()獲取正在競(jìng)爭(zhēng)的鎖。帶有“_slow”后綴的函數(shù)不是必需的,因?yàn)榭梢哉{(diào)用函數(shù)ww_mutex_lock()獲取正在競(jìng)爭(zhēng)的鎖。帶有“_slow”后綴的函數(shù)的優(yōu)點(diǎn)是接口安全,如下。
- 函數(shù)ww_mutex_lock()有一個(gè)整數(shù)返回值,而函數(shù)ww_mutex_lock_slow()沒(méi)有返回值。
- 當(dāng)開(kāi)啟調(diào)試的時(shí)候,函數(shù)ww_mutex_lock_slow()檢查所有已經(jīng)獲取的鎖已經(jīng)被釋放,并且確保進(jìn)程阻塞在正在競(jìng)爭(zhēng)的鎖上面。
(3) 只獲取一個(gè)傷害/等待互斥鎖,和獲取普通的互斥鎖完全相同。調(diào)用函數(shù)ww_mutex_lock(),把獲取上下文指定為空指針。
傷害/等待互斥鎖的使用方法如下。(1) 定義一個(gè)鎖類,鎖類在初始化獲取上下文的時(shí)候需要,鎖類也指定算法:等待-死亡(Wait-Die)或傷害-等待(Wound-Wait)。
/* 指定等待-死亡算法 */
static DEFINE_WD_CLASS(my_class);
/* 指定傷害-等待算法 */
staticDEFINE_WW_CLASS(my_class);
(2) 初始化一個(gè)獲取上下文,鎖類會(huì)給獲取上下文分配一張門(mén)票。
void ww_acquire_init(struct ww_acquire_ctx *ctx, struct ww_class *ww_class);
(3) 獲取鎖,返回0表示獲取成功,返回“-EDEADLK”表示檢測(cè)出死鎖。
int ww_mutex_lock(struct ww_mutex *lock, struct ww_acquire_ctx *ctx);
(4) 獲取需要的所有鎖以后,標(biāo)記獲取階段結(jié)束。目前這個(gè)函數(shù)沒(méi)有執(zhí)行任何操作,但是將來(lái)可能改變。
void ww_acquire_done(struct ww_acquire_ctx *ctx);
(5) 釋放鎖。
void ww_mutex_unlock(struct ww_mutex *lock);
(6) 釋放所有鎖以后,釋放獲取上下文。
void ww_acquire_fini(struct ww_acquire_ctx *ctx);
下面是一個(gè)例子,注意:調(diào)用函數(shù)ww_mutex_lock()申請(qǐng)鎖失敗以后,應(yīng)該先釋放已經(jīng)獲取的鎖,然后調(diào)用慢路徑函數(shù)ww_mutex_lock_slow()獲取正在競(jìng)爭(zhēng)的鎖,最后獲取其它鎖。重新開(kāi)始申請(qǐng)鎖的時(shí)候必須改變申請(qǐng)順序,因?yàn)槿绻凑赵瓉?lái)的順序申請(qǐng)鎖,那么會(huì)把剛釋放的鎖搶回來(lái)。
責(zé)任編輯:haq/* 第1步:定義鎖類,指定傷害-等待算法。*/
static DEFINE_WW_CLASS(ww_class);
struct obj {
struct ww_mutex lock;
/* obj data */
};
struct obj_entry {
struct list_head head;
struct obj *obj;
};
int lock_objs(struct list_head *list, struct ww_acquire_ctx *ctx)
{
struct obj *res_obj = NULL;
struct obj_entry *contended_entry = NULL;
struct obj_entry *entry;
int ret;
/* 第2步:初始化獲取上下文。*/
ww_acquire_init(ctx, &ww_class);
/* 第3步:獲取鎖。*/
retry:
list_for_each_entry(entry, list, head) {
if (entry->obj == res_obj) {
res_obj = NULL;
continue;
}
ret = ww_mutex_lock(&entry->obj->lock, ctx);
if (ret < 0) {
contended_entry = entry;
goto err;
}
}
/* 第4步:標(biāo)記獲取階段結(jié)束。*/
ww_acquire_done(ctx);
return 0;
err:
/* 回滾,釋放已經(jīng)獲取的鎖。*/
list_for_each_entry_continue_reverse(entry, list, head) {
ww_mutex_unlock(&entry->obj->lock);
}
if (res_obj) {
ww_mutex_unlock(&res_obj->lock);
}
if (ret == -EDEADLK) {
/* 使用慢路徑獲取鎖函數(shù)獲取正在競(jìng)爭(zhēng)的鎖。*/
ww_mutex_lock_slow(&contended_entry->obj->lock, ctx);
res_obj = contended_entry->obj;
/* 獲取其它鎖。*/
goto retry;
}
ww_acquire_fini(ctx);
return ret;
}
void unlock_objs(struct list_head *list, struct ww_acquire_ctx *ctx)
{
struct obj_entry *entry;
/* 第5步:釋放鎖。*/
list_for_each_entry (entry, list, head) {
ww_mutex_unlock(&entry->obj->lock);
}
/* 第6步:釋放獲取上下文。*/
ww_acquire_fini(ctx);
}
-
鎖相環(huán)
+關(guān)注
關(guān)注
35文章
584瀏覽量
87769 -
Linux
+關(guān)注
關(guān)注
87文章
11304瀏覽量
209523
原文標(biāo)題:傷害/等待互斥鎖
文章出處:【微信號(hào):LinuxDev,微信公眾號(hào):Linux閱碼場(chǎng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論