當(dāng)前位置:首頁 > 嵌入式 > 嵌入式分享
[導(dǎo)讀]今天談?wù)刲inux中常見并發(fā)訪問的保護(hù)機(jī)制設(shè)計(jì)原理。這既可以考察面試者對(duì)鎖的原理的理解,又可以考察面試者編程技能)。我們拋開linux中匯編代碼。用C語言為大家呈現(xiàn)背后實(shí)現(xiàn)的原理。同時(shí),文章中的代碼都沒有考慮并發(fā)情況(例如某些操作需要原子性,或者數(shù)據(jù)需要保護(hù)等)。

今天談?wù)刲inux中常見并發(fā)訪問的保護(hù)機(jī)制設(shè)計(jì)原理。這既可以考察面試者對(duì)鎖的原理的理解,又可以考察面試者編程技能)。我們拋開linux中匯編代碼。用C語言為大家呈現(xiàn)背后實(shí)現(xiàn)的原理。同時(shí),文章中的代碼都沒有考慮并發(fā)情況(例如某些操作需要原子性,或者數(shù)據(jù)需要保護(hù)等)。

注:部分代碼都是根據(jù)ARM64架構(gòu)匯編代碼翻譯成C語言并經(jīng)過精簡(jiǎn)(例如:spin lock、read-write lock)。也有部分代碼實(shí)現(xiàn)是為了呈現(xiàn)背后設(shè)計(jì)的原理自己編寫的,而不是精簡(jiǎn)linux中實(shí)現(xiàn)的代碼(例如mutex)。

自旋鎖(spin lock)

自旋鎖是linux中使用非常頻繁的鎖,原理簡(jiǎn)單。當(dāng)進(jìn)程A申請(qǐng)鎖成功后,進(jìn)程B申請(qǐng)鎖就會(huì)失敗,但是不會(huì)調(diào)度,原地自旋。就在原地轉(zhuǎn)到天昏地暗只為等到進(jìn)程A釋放鎖。由于不會(huì)睡眠和調(diào)度的特性,在中斷上下文中,數(shù)據(jù)的保護(hù)一般都是選擇自旋鎖。如果有多個(gè)進(jìn)程去申請(qǐng)鎖。當(dāng)?shù)谝粋€(gè)申請(qǐng)鎖成功的線程在釋放的時(shí)候,其他進(jìn)程是競(jìng)爭(zhēng)的關(guān)系。因此是一種不公平。所以現(xiàn)在的linux采用的是排隊(duì)機(jī)制。先到先得。誰先申請(qǐng),誰就先得到鎖。

原理

舉個(gè)例子,大家應(yīng)該都去過銀行辦業(yè)務(wù)吧。銀行的辦事大廳一般會(huì)有幾個(gè)窗口同步進(jìn)行。今天很不巧,只有一個(gè)窗口提供服務(wù)?,F(xiàn)在的銀行服務(wù)都是采用取號(hào)排隊(duì),叫號(hào)服務(wù)的方式。當(dāng)你去銀行辦理業(yè)務(wù)的時(shí)候,首先會(huì)去取號(hào)機(jī)器領(lǐng)取小票,上面寫著你排多少號(hào)。然后你就可以排隊(duì)等待了。一般還會(huì)有個(gè)顯示屏,上面會(huì)顯示一個(gè)數(shù)字(例如:"請(qǐng)xxx號(hào)到1號(hào)窗口辦理"),代表當(dāng)前可以被服務(wù)顧客的排隊(duì)號(hào)碼。每辦理完一個(gè)顧客的業(yè)務(wù),顯示屏上面的數(shù)字都會(huì)增加1。等待的顧客都會(huì)對(duì)比自己手上寫的編號(hào)和顯示屏上面是否一致,如果一致的話,就可以去前臺(tái)辦理業(yè)務(wù)了?,F(xiàn)在早上剛開業(yè),顧客A是今天的第一個(gè)顧客,去取號(hào)機(jī)器領(lǐng)取0號(hào)(next計(jì)數(shù))小票,然后看到顯示屏上顯示0(owner計(jì)數(shù)),顧客A就知道現(xiàn)在輪到自己辦理業(yè)務(wù)了。顧客A到前臺(tái)辦理業(yè)務(wù)(持有鎖)中,顧客B來了。同樣,顧客B去取號(hào)機(jī)器拿到1號(hào)(next計(jì)數(shù))小票。然后乖乖的坐在旁邊等候。顧客A依然在辦理業(yè)務(wù)中,此時(shí)顧客C也來了。顧客C去取號(hào)機(jī)器拿到2號(hào)(next計(jì)數(shù))小票。顧客C也乖乖的找個(gè)座位繼續(xù)等待。終于,顧客A的業(yè)務(wù)辦完了(釋放鎖)。然后,顯示屏上面顯示1(owner計(jì)數(shù))。顧客B和C都對(duì)比顯示屏上面的數(shù)字和自己手中小票的數(shù)字是否相等。顧客B終于可以辦理業(yè)務(wù)了(持有鎖)。顧客C依然等待中。顧客B的業(yè)務(wù)辦完了(釋放鎖)。然后,顯示屏上面顯示2(owner計(jì)數(shù))。顧客C終于開始辦理業(yè)務(wù)(持有鎖)。顧客C的業(yè)務(wù)辦完了(釋放鎖)。3個(gè)顧客都辦完了業(yè)務(wù)離開了。只留下一個(gè)銀行柜臺(tái)服務(wù)員。最終,顯示屏上面顯示3(owner計(jì)數(shù))。取號(hào)機(jī)器的下一個(gè)排隊(duì)號(hào)也是3號(hào)(next計(jì)數(shù))。無人辦理業(yè)務(wù)(鎖是釋放狀態(tài))。

linux中針對(duì)每一個(gè)spin lock會(huì)有兩個(gè)計(jì)數(shù)。分別是next和owner(初始值為0)。進(jìn)程A申請(qǐng)鎖時(shí),會(huì)判斷next和owner的值是否相等。如果相等就代表鎖可以申請(qǐng)成功,否則原地自旋。直到owner和next的值相等才會(huì)退出自旋。假設(shè)進(jìn)程A申請(qǐng)鎖成功,然后會(huì)next加1。此時(shí)owner值為0,next值為1。進(jìn)程B也申請(qǐng)鎖,保存next得值到局部變量tmp(tmp = 1)中。由于next和owner值不相等,因此原地自旋讀取owner的值,判斷owner和tmp是否相等,直到相等退出自旋狀態(tài)。當(dāng)然next的值還是加1,變成2。進(jìn)程A釋放鎖,此時(shí)會(huì)將owner的值加1,那么此時(shí)B進(jìn)程的owner和tmp的值都是1,因此B進(jìn)程獲得鎖。當(dāng)B進(jìn)程釋放鎖后,同樣會(huì)將owner的值加1。最后owner和next都等于2,代表沒有進(jìn)程持有鎖。next就是一個(gè)記錄申請(qǐng)鎖的次數(shù),而owner是持有鎖進(jìn)程的計(jì)數(shù)值。

實(shí)現(xiàn)

我們首先定義描述自旋鎖的結(jié)構(gòu)體arch_spinlock_t。

typedef struct {

union {

unsigned int slock;

struct __raw_tickets {

unsigned short owner;

unsigned short next;

} TIckets;

};

} arch_spinlock_t;

如上面的原理描述,我們需要兩個(gè)計(jì)數(shù),分別是owner和next。slock所占內(nèi)存區(qū)域覆蓋owner和next(據(jù)說C語言學(xué)好的都能看得懂)。下面實(shí)現(xiàn)申請(qǐng)鎖操作 arch_spin_lock。

staTIc inline void arch_spin_lock(arch_spinlock_t *lock)

{

arch_spinlock_t old_lock;

old_lock.slock = lock->slock; /* 1 */

lock->TIckets.next++; /* 2 */

while (old_lock.TIckets.next != old_lock.tickets.owner) { /* 3 */

wfe(); /* 4 */

old_lock.tickets.owner = lock->tickets.owner; /* 5 */

}

}

繼續(xù)上面的舉例。顧客從取號(hào)機(jī)器得到排隊(duì)號(hào)。

取號(hào)機(jī)器更新下個(gè)顧客將要拿到的排隊(duì)號(hào)。

看一下顯示屏,判斷是否輪到自己了。

wfe()函數(shù)是指ARM64架構(gòu)的WFE(wait for event)匯編指令。WFE是讓ARM核進(jìn)入低功耗模式的指令。當(dāng)進(jìn)程拿不到鎖的時(shí)候,原地自旋不如cpu睡眠。節(jié)能。睡下去之后,什么時(shí)候醒來呢?就是等到持有鎖的進(jìn)程釋放的時(shí)候,醒過來判斷是否可以持有鎖。如果不能獲得鎖,繼續(xù)睡眠即可。這里就相當(dāng)于顧客先小憩一會(huì),等到廣播下一位排隊(duì)者的時(shí)候,醒來看看是不是自己。

前臺(tái)已經(jīng)為上一個(gè)顧客辦理完成業(yè)務(wù),剩下排隊(duì)的顧客都要抬頭看一下顯示屏是不是輪到自己了。

釋放鎖的操作就非常簡(jiǎn)單了。還記得上面銀行辦理業(yè)務(wù)的例子嗎?釋放鎖的操作僅僅是顯示屏上面的排隊(duì)號(hào)加1。我們僅僅需要將owner計(jì)數(shù)加1即可。arch_spin_unlock實(shí)現(xiàn)如下。

static inline void arch_spin_unlock(arch_spinlock_t *lock)

{

lock->tickets.owner++;

sev();

}

sev()函數(shù)是指ARM64架構(gòu)的SEV匯編指令。當(dāng)進(jìn)程無法獲取鎖的時(shí)候會(huì)使用WFE指令使CPU睡眠?,F(xiàn)在釋放鎖了,自然要喚醒所有睡眠的CPU醒來檢查自己是不是可以獲取鎖。

信號(hào)量(semaphore)

信號(hào)量(semaphore)是進(jìn)程間通信處理同步互斥的機(jī)制。是在多線程環(huán)境下使用的一種措施,它負(fù)責(zé)協(xié)調(diào)各個(gè)進(jìn)程,以保證他們能夠正確、合理的使用公共資源。 它和spin lock最大的不同之處就是:無法獲取信號(hào)量的進(jìn)程可以睡眠,因此會(huì)導(dǎo)致系統(tǒng)調(diào)度。

原理

信號(hào)量一般可以用來標(biāo)記可用資源的個(gè)數(shù)。老規(guī)矩,還是舉個(gè)例子。假設(shè)圖書館有2本《C語言從入門到放棄》書籍。A同學(xué)想學(xué)C語言,于是發(fā)現(xiàn)這本書特別的好。于是就去學(xué)校的圖書館借書,A同學(xué)成功的從圖書館借走一本。這時(shí),A同學(xué)室友B同學(xué)發(fā)現(xiàn)A同學(xué)竟然在偷偷的學(xué)習(xí)武功秘籍(C語言)。于是,B同學(xué)也去借一本。此時(shí),圖書館已經(jīng)沒有書了。C同學(xué)也想借這本書,可能是這本書太火了。圖書館管理員告訴C同學(xué),圖書館這本書都被借走了。如果有同學(xué)換回來,會(huì)第一時(shí)間通知你。于是,管理員就把C同學(xué)的信息登記先來,以備后續(xù)通知C同學(xué)來借書。所以,C同學(xué)只能悲傷的走了(如果是自旋鎖的原理的話,那么C同學(xué)將會(huì)端個(gè)小板凳坐在圖書館,一直要等到A同學(xué)或者B同學(xué)還書并借走)。

實(shí)現(xiàn)

為了記錄可用資源的數(shù)量,我們肯定需要一個(gè)count計(jì)數(shù),標(biāo)記當(dāng)前可用資源數(shù)量。當(dāng)然還要一個(gè)可以像圖書管理員一樣的筆記本功能。用來記錄等待借書的同學(xué)。所以,一個(gè)雙向鏈表即可。因此只需要一個(gè)count計(jì)數(shù)和等待進(jìn)程的鏈表頭即可。描述信號(hào)量的結(jié)構(gòu)體如下。

struct semaphore {

unsigned int count;

struct list_head wait_list;

};

在linux中,每個(gè)進(jìn)程就相當(dāng)于是每個(gè)借書的同學(xué)。通知一個(gè)同學(xué),就相當(dāng)于喚醒這個(gè)進(jìn)程。因此,我們還需要一個(gè)結(jié)構(gòu)體記錄當(dāng)前的進(jìn)程信息(task_struct)。

struct semaphore_waiter {

struct list_head list;

struct task_struct *task;

};

struct semaphore_waiter的list成員是當(dāng)進(jìn)程無法獲取信號(hào)量的時(shí)候掛入semaphore的wait_list成員。task成員就是記錄后續(xù)被喚醒的進(jìn)程信息。

一切準(zhǔn)備就緒,現(xiàn)在就可以實(shí)現(xiàn)信號(hào)量的申請(qǐng)函數(shù)。

void down(struct semaphore *sem)

{

struct semaphore_waiter waiter;

if (sem->count > 0) {

sem->count--; /* 1 */

return;

}

waiter.task = current; /* 2 */

list_add_tail(&waiter.list, &sem->wait_list); /* 2 */

schedule(); /* 3 */

}

如果信號(hào)量標(biāo)記的資源還有剩余,自然可以成功獲取信號(hào)量。只需要遞減可用資源計(jì)數(shù)。

既然無法獲取信號(hào)量,就需要將當(dāng)前進(jìn)程掛入信號(hào)量的等待隊(duì)列鏈表上。

schedule()主要是觸發(fā)任務(wù)調(diào)度的示意函數(shù),主動(dòng)讓出CPU使用權(quán)。在讓出之前,需要將當(dāng)前進(jìn)程從運(yùn)行隊(duì)列上移除。

釋放信號(hào)的實(shí)現(xiàn)也是比較簡(jiǎn)單。實(shí)現(xiàn)如下。

void up(struct semaphore *sem)

{

struct semaphore_waiter waiter;

if (list_empty(&sem->wait_list)) {

sem->count++; /* 1 */

return;

}

waiter = list_first_entry(&sem->wait_list, struct semaphore_waiter, list);

list_del(&waiter->list); /* 2 */

wake_up_process(waiter->task); /* 2 */

}

如果等待鏈表沒有進(jìn)程,那么自然只需要增加資源計(jì)數(shù)。

從等待進(jìn)程鏈表頭取出第一個(gè)進(jìn)程,并從鏈表上移除。然后就是喚醒該進(jìn)程。

讀寫鎖(read-write lock)

不管是自旋鎖還是信號(hào)量在同一時(shí)間只能有一個(gè)進(jìn)程進(jìn)入臨界區(qū)。對(duì)于有些情況,我們是可以區(qū)分讀寫操作的。因此,我們希望對(duì)于讀操作的進(jìn)程可以并發(fā)進(jìn)行。對(duì)于寫操作只限于一個(gè)進(jìn)程進(jìn)入臨界區(qū)。而這種同步機(jī)制就是讀寫鎖。讀寫鎖一般具有以下幾種性質(zhì)。

同一時(shí)間有且僅有一個(gè)寫進(jìn)程進(jìn)入臨界區(qū)。

在沒有寫進(jìn)程進(jìn)入臨界區(qū)的時(shí)候,同時(shí)可以有多個(gè)讀進(jìn)程進(jìn)入臨界區(qū)。

讀進(jìn)程和寫進(jìn)程不可以同時(shí)進(jìn)入臨界區(qū)。

讀寫鎖有兩種,一種是信號(hào)量類型,另一種是spin lock類型。下面以spin lock類型講解。

原理

老規(guī)矩,還是舉個(gè)例子理解讀寫鎖。我絞盡腦汁才想到一個(gè)比較貼切的例子。這個(gè)例子來源于生活。我發(fā)現(xiàn)公司一般都會(huì)有保潔阿姨打掃廁所。如果以男廁所為例的話,我覺得男士進(jìn)入廁所就相當(dāng)于讀者進(jìn)入臨界區(qū)。因?yàn)榭梢杂卸鄠€(gè)男士進(jìn)廁所。而保潔阿姨進(jìn)入男士廁所就相當(dāng)于寫者進(jìn)入臨界區(qū)。假設(shè)A男士發(fā)現(xiàn)保潔阿姨不在打掃廁所,就進(jìn)入廁所。隨后B和C同時(shí)也進(jìn)入廁所。然后保潔阿姨準(zhǔn)備打掃廁所,發(fā)現(xiàn)有男士在廁所里面,因此只能在門口等待。ABC都離開了廁所。保潔阿姨迅速進(jìn)入廁所打掃。然后D男士去上廁所,發(fā)現(xiàn)保潔阿姨在里面?;伊锪锏某鰜砹嗽陂T口等著。現(xiàn)在體會(huì)到了寫者(保潔阿姨)具有排他性,讀者(男士)可以并發(fā)進(jìn)入臨界區(qū)了吧。

既然我們?cè)试S多個(gè)讀者進(jìn)入臨界區(qū),因此我們需要一個(gè)計(jì)數(shù)統(tǒng)計(jì)讀者的個(gè)數(shù)。同時(shí),由于寫者永遠(yuǎn)只存在一個(gè)進(jìn)入臨界區(qū),因此只需要一個(gè)bit標(biāo)記是否有寫進(jìn)程進(jìn)入臨界區(qū)。所以,我們可以將兩個(gè)計(jì)數(shù)合二為一。只需要1個(gè)unsigned int類型即可。最高位(bit31)代表是否有寫者進(jìn)入臨界區(qū),低31位(0~30bit)統(tǒng)計(jì)讀者個(gè)數(shù)。

+----+-------------------------------------------------+

| 31 | 30 0 |

+----+-------------------------------------------------+

| |

| +----> [0:30] Read Thread Counter

+-------------------------> [31] Write Thread Counter

實(shí)現(xiàn)

描述讀寫鎖只需要1個(gè)變量即可,因此我們可以定義讀寫鎖的結(jié)構(gòu)體如下。

typedef struct {

volatile unsigned int lock;

} arch_rwlock_t;

既然區(qū)分讀寫操作,因此肯定會(huì)有兩個(gè)申請(qǐng)鎖函數(shù),分別是讀和寫。首先,我們看一下read_lock操作的實(shí)現(xiàn)。

static inline void arch_read_lock(arch_rwlock_t *rw)

{

unsigned int tmp;

sevl(); /* 1 */

do {

wfe();

tmp = rw->lock;

tmp++; /* 2 */

} while(tmp & (1 << 31)); /* 3 */

rw->lock = tmp;

}

sevl()函數(shù)是ARM64架構(gòu)中SEVL匯編指令。SEVL和SEV的區(qū)別是,SEVL僅僅修改本地CPU的PE寄存器值,這樣下面的WFE指令第一次執(zhí)行的時(shí)候不會(huì)睡眠。

增加讀者計(jì)數(shù),最后會(huì)更新到rw->lock中。

更新rw->lock前提是沒有寫者,因此這里會(huì)判斷是否有寫者已經(jīng)進(jìn)入臨界區(qū)(判斷方法是rw->lock變量bit31的值)。如果,有寫者已經(jīng)進(jìn)入臨界區(qū),就在這里循環(huán),并WFE指令睡眠。類似上面介紹的spin lock實(shí)現(xiàn)。

當(dāng)讀進(jìn)程離開臨界區(qū)的時(shí)候會(huì)調(diào)用read_unlock釋放鎖。read_unlock實(shí)現(xiàn)如下。

static inline void arch_read_unlock(arch_rwlock_t *rw)

{

rw->lock--;

sev();

}

實(shí)現(xiàn)很簡(jiǎn)單,和spin_unlock如出一轍。遞減讀者計(jì)數(shù),然后使用SEV指令喚醒所有的CPU,檢查等待狀態(tài)的進(jìn)程是否可以獲取鎖。

讀操作看完了,我們看看寫操作是如何實(shí)現(xiàn)的。arch_write_lock實(shí)現(xiàn)如下。

static inline void arch_write_lock(arch_rwlock_t *rw)

{

unsigned int tmp;

sevl();

do {

wfe();

tmp = rw->lock;

} while(tmp); /* 1 */

rw->lock = 1 << 31; /* 2 */

}

由于寫者是排他的(讀者和寫者都不能有),因此這里只有rw->lock的值為0,當(dāng)前的寫者才可以進(jìn)入臨界區(qū)。

置位rw->lock的bit31,代表有寫者進(jìn)入臨界區(qū)。

當(dāng)寫進(jìn)程離開臨界區(qū)的時(shí)候會(huì)調(diào)用write_unlock釋放鎖。write_unlock實(shí)現(xiàn)如下。

static inline void arch_write_unlock(arch_rwlock_t *rw)

{

rw->lock = 0; /* 1 */

sev(); /* 2 */

}

同樣由于寫者是排他的,因此只需要將rw->lock置0即可。代表沒有任何進(jìn)程進(jìn)入臨界區(qū)。畢竟是因?yàn)橥粫r(shí)間只能有一個(gè)寫者進(jìn)入臨界區(qū),當(dāng)這個(gè)寫者離開臨界區(qū)的時(shí)候,肯定是意味著現(xiàn)在沒有任何進(jìn)程進(jìn)入臨界區(qū)。

使用SEV指令喚醒所有的CPU,檢查等待狀態(tài)的進(jìn)程是否可以獲取鎖。

以上的代碼實(shí)現(xiàn)其實(shí)會(huì)導(dǎo)致寫進(jìn)程餓死現(xiàn)象。例如,A、B、C三個(gè)進(jìn)程進(jìn)入讀臨界區(qū),D進(jìn)程嘗試獲得寫鎖,此時(shí)只能等待A、B、C三個(gè)進(jìn)程退出臨界區(qū)。如果在退出之前又有F、G進(jìn)程進(jìn)入讀臨界區(qū),那么將出現(xiàn)D進(jìn)程餓死現(xiàn)象。

互斥量(mutex)

前文提到的semaphore在初始化count計(jì)數(shù)的時(shí)候,可以分為計(jì)數(shù)信號(hào)量和互斥信號(hào)量(二值信號(hào)量)。mutex和初始化計(jì)數(shù)為1的二值信號(hào)量有很大的相似之處。他們都可以用做資源互斥。但是mutex卻有一個(gè)特殊的地方:只有持鎖者才能解鎖。但是,二值信號(hào)量卻可以在一個(gè)進(jìn)程中獲取信號(hào)量,在另一個(gè)進(jìn)程中釋放信號(hào)量。如果是應(yīng)用在嵌入式應(yīng)用的RTOS,針對(duì)mutex的實(shí)現(xiàn)還會(huì)考慮優(yōu)先級(jí)反轉(zhuǎn)問題。

原理

既然mutex是一種二值信號(hào)量,因此就不需要像semaphore那樣需要一個(gè)count計(jì)數(shù)。由于mutex具有“持鎖者才能解鎖”的特點(diǎn),所以我們需要一個(gè)變量owner記錄持鎖進(jìn)程。釋放鎖的時(shí)候必須是同一個(gè)進(jìn)程才能釋放。當(dāng)然也需要一個(gè)鏈表頭,主要用來便利睡眠等待的進(jìn)程。原理和semaphore及其相似,因此在代碼上也有體現(xiàn)。

實(shí)現(xiàn)

mutex的實(shí)現(xiàn)代碼和linux中實(shí)現(xiàn)會(huì)有差異,但是依然可以為你呈現(xiàn)設(shè)計(jì)的原理。下面的設(shè)計(jì)代碼更像是部分RTOS中的代碼。mutex和semaphore一樣,我們需要兩個(gè)類似的結(jié)構(gòu)體分別描述mutex。

struct mutex_waiter {

struct list_head list;

struct task_struct *task;

};

struct mutex {

long owner;

struct list_head wait_list;

};

struct mutex_waiter的list成員是當(dāng)進(jìn)程無法獲取互斥量的時(shí)候掛入mutex的wait_list鏈表。

首先實(shí)現(xiàn)申請(qǐng)互斥量的函數(shù)。

void mutex_take(struct mutex *mutex)

{

struct mutex_waiter waiter;

if (!mutex->owner) {

mutex->owner = (long)current; /* 1 */

return;

}

waiter.task = current;

list_add_tail(&waiter.list, &mutex->wait_list); /* 2 */

schedule(); /* 2 */

}

當(dāng)mutex->owner的值為0的時(shí)候,代表沒有任何進(jìn)程持有鎖。因此可以直接申請(qǐng)成功。然后,記錄當(dāng)前申請(qǐng)鎖進(jìn)程的task_struct。

既然不能獲取互斥量,自然就需要睡眠等待,掛入等待鏈表。

互斥量的釋放代碼實(shí)現(xiàn)也同樣和semaphore有很多相似之處。不信,你看。

int mutex_release(struct mutex *mutex)

{

struct mutex_waiter *waiter;

if (mutex->owner != (long)current) /* 1 */

return -1;

if (list_empty(&mutex->wait_list)) {

mutex->owner = 0; /* 2 */

return 0;

}

waiter = list_first_entry(&mutex->wait_list, struct mutex_waiter, list);

list_del(&waiter->list);

mutex->owner = (long)waiter->task; /* 3 */

wake_up_process(waiter->task); /* 4 */

return 0;

}

mutex具有“持鎖者才能解鎖”的特點(diǎn)就是在這行代碼體現(xiàn)。

如果等待鏈表沒有進(jìn)程,那么自然只需要將mutex->owner置0,代表沒有鎖是釋放狀態(tài)。

mutex->owner的值改成當(dāng)前可以持鎖進(jìn)程的task_struct。

從等待進(jìn)程鏈表取出第一個(gè)進(jìn)程,并從鏈表上移除。然后就是喚醒該進(jìn)程。

這樣你對(duì)這個(gè)機(jī)制有所了解了嗎?

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

倫敦2024年8月29日 /美通社/ -- 英國(guó)汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對(duì)日本游戲市場(chǎng)的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對(duì)環(huán)境變化,經(jīng)營(yíng)業(yè)績(jī)穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤(rùn)率延續(xù)升勢(shì) 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長(zhǎng) 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競(jìng)爭(zhēng)力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競(jìng)爭(zhēng)優(yōu)勢(shì)...

關(guān)鍵字: 通信 BSP 電信運(yùn)營(yíng)商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國(guó)電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場(chǎng) NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長(zhǎng)三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡(jiǎn)稱"軟通動(dòng)力")與長(zhǎng)三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉