网站黄色在线观看视频,男人和女人操逼有免费的视频吗2018高清,91熟女丨老女人丨高潮丰满,丝袜高潮流白浆潮喷在线播放

中國站

中國站

國際版

聯(lián)系我們

400-002-9968

售前咨詢

售后服務(wù)

注冊 登錄

博客 > Linux驅(qū)動知識:Linux內(nèi)核互斥鎖定義、作用和使用實例

Linux驅(qū)動知識:Linux內(nèi)核互斥鎖定義、作用和使用實例

  • 標簽:
  • Linux驅(qū)動
  • Linux內(nèi)核
  • 互斥鎖
  • Mutex
  • Linux

瀏覽量:1809次評論:0次

作者:銳成網(wǎng)絡(luò)整理時間:2024-06-19 17:01:58

Linux內(nèi)核開發(fā)中,互斥鎖Mutex,也叫做互斥體,作為一種重要的同步機制,扮演著保護關(guān)鍵代碼區(qū)域不被并發(fā)訪問的關(guān)鍵角色。本文將深度探究Linux內(nèi)核互斥鎖的定義、作用、優(yōu)點、作用以及鎖定和解鎖使用實例。

互斥鎖Mutex概述

信號量是在并行處理環(huán)境中對多個處理器訪問某個公共資源進行保護的機制,mutex用于互斥操作。信號量的count初始化為1,down()/up()也可以實現(xiàn)類似mutex的作用。

mutex的語義相對于信號量要簡單輕便一些,在鎖爭用激烈的測試場景下,mutex比信號量執(zhí)行速度更快,可擴展性更好,另外mutex數(shù)據(jù)結(jié)構(gòu)的定義比信號量小。

Linux驅(qū)動知識:Linux內(nèi)核互斥鎖定義、作用和使用實例

互斥鎖Mutex的優(yōu)點

mutex和信號量相比要高效的多:

mutex最先實現(xiàn)自旋等待機制

mutex在睡眠之前嘗試獲取鎖

mutex實現(xiàn)MCS所來避免多個CPU爭用鎖而導(dǎo)致CPU高速緩存顛簸現(xiàn)象。

互斥鎖Mutex的使用注意事項:

同一時刻只有一個線程可以持有mutex。

只有鎖持有者可以解鎖。不能再一個進程中持有mutex,在另外一個進程中釋放他。

不允許遞歸地加鎖和解鎖。

當(dāng)進程持有mutex時,進程不可以退出。

mutex必須使用官方API來初始化。

mutex可以睡眠,所以不允許在中斷處理程序或者中斷下半部中使用,例如tasklet、定時器等。

目錄:

/linux/include/linux/mutex.h

/*
 * Simple, straightforward mutexes with strict semantics:
 *
 * - only one task can hold the mutex at a time
 * - only the owner can unlock the mutex
 * - multiple unlocks are not permitted
 * - recursive locking is not permitted
 * - a mutex object must be initialized via the API
 * - a mutex object must not be initialized via memset or copying
 * - task may not exit with mutex held
 * - memory areas where held locks reside must not be freed
 * - held mutexes must not be reinitialized
 * - mutexes may not be used in hardware or software interrupt
 *   contexts such as tasklets and timers
 *
 * These semantics are fully enforced when DEBUG_MUTEXES is
 * enabled. Furthermore, besides enforcing the above rules, the mutex
 * debugging code also implements a number of additional features
 * that make lock debugging easier and faster:
 *
 * - uses symbolic names of mutexes, whenever they are printed in debug output
 * - point-of-acquire tracking, symbolic lookup of function names
 * - list of all locks held in the system, printout of them
 * - owner tracking
 * - detects self-recursing locks and prints out all relevant info
 * - detects multi-task circular deadlocks and prints out all affected
 *   locks and tasks (and only those tasks)
 */
struct mutex {
  /* 1: unlocked, 0: locked, negative: locked, possible waiters */
  atomic_t    count;
  spinlock_t    wait_lock;
  struct list_head  wait_list;
#if defined(CONFIG_DEBUG_MUTEXES) || defined(CONFIG_SMP)
  struct task_struct  *owner;
#endif
#ifdef CONFIG_MUTEX_SPIN_ON_OWNER
  void      *spin_mlock;  /* Spinner MCS lock */
#endif
#ifdef CONFIG_DEBUG_MUTEXES
  const char     *name;
  void      *magic;
#endif
#ifdef CONFIG_DEBUG_LOCK_ALLOC
  struct lockdep_map  dep_map;
#endif
};

 

互斥鎖Mutex作用及訪問規(guī)則:

互斥鎖主要用于實現(xiàn)內(nèi)核中的互斥訪問功能。內(nèi)核互斥鎖是在原子 API 之上實現(xiàn)的,但這對于內(nèi)核用戶是不可見的。

對它的訪問必須遵循一些規(guī)則:同一時間只能有一個任務(wù)持有互斥鎖,而且只有這個任務(wù)可以對互斥鎖進行解鎖?;コ怄i不能進行遞歸鎖定或解鎖。一個互斥鎖對象必須通過其API初始化,而不能使用memset或復(fù)制初始化。一個任務(wù)在持有互斥鎖的時候是不能結(jié)束的?;コ怄i所使用的內(nèi)存區(qū)域是不能被釋放的。使用中的互斥鎖是不能被重新初始化的。并且互斥鎖不能用于中斷上下文。

互斥鎖比當(dāng)前的內(nèi)核信號量選項更快,并且更加緊湊。

互斥鎖Mutex的使用

初始化

靜態(tài)定義如下:

DEFINE_MUTEX(name);

動態(tài)初始化mutex,如下:

mutex_init(&mutex);

具體實現(xiàn)如下:

#define mutex_init(mutex) \
do {       \
 static struct lock_class_key __key;  \
       \
 __mutex_init((mutex), #mutex, &__key);  \
} while (0)

void
__mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key)
{
 atomic_set(&lock->count, 1);
 spin_lock_init(&lock->wait_lock);
 INIT_LIST_HEAD(&lock->wait_list);
 mutex_clear_owner(lock);
#ifdef CONFIG_MUTEX_SPIN_ON_OWNER
 lock->spin_mlock = NULL;
#endif

 debug_mutex_init(lock, name, key);
}

申請互斥鎖

mutex操作列表如下:

方法

描述

mutex_lock(struct mutex*)

為指定的mutex上鎖,如果不可用則睡眠

mutex_unlock(struct mutex*)

為指定的mutex解鎖

mutex_trylock(struct mutex*)

視圖獲取指定的mutex,如果成功則返回1;否則鎖被獲取,返回值是0

mutex_is_lock(struct mutex*)

如果鎖已被征用,則返回1;否則返回0

mutex的簡潔性和高效性源自于相比使用信號量更多的受限性。它不同于信號量,因為mutex僅僅實現(xiàn)了Dijkstra設(shè)計初衷中的最基本的行為。因此mutex的使用場景相對而言更嚴格。

(1)代碼:linux/kernel/mutex.c

void inline fastcall __sched mutex_lock(struct mutex *lock);   
 //獲取互斥鎖。

實際上是先給count做自減操作,然后使用本身的自旋鎖進入臨界區(qū)操作。首先取得count的值,在將count置為-1,判斷如果原來count的置為1,也即互斥鎖可以獲得,則直接獲取,跳出。否則進入循環(huán)反復(fù)測試互斥鎖的狀態(tài)。在循環(huán)中,也是先取得互斥鎖原來的狀態(tài),在將其之為-1,判斷如果可以獲取(等于1),則退出循環(huán),否則設(shè)置當(dāng)前進程的狀態(tài)為不可中斷狀態(tài),解鎖自身的自旋鎖,進入睡眠狀態(tài),待被在調(diào)度喚醒時,再獲得自身的自旋鎖,進入新一次的查詢其自身狀態(tài)(該互斥鎖的狀態(tài))的循環(huán)。

(2)具體參見linux/kernel/mutex.c

int fastcall __sched mutex_lock_interruptible(struct mutex *lock);

和mutex_lock()一樣,也是獲取互斥鎖。在獲得了互斥鎖或進入睡眠直到獲得互斥鎖之后會返回0。如果在等待獲取鎖的時候進入睡眠狀態(tài)收到一個信號(被信號打斷睡眠),則返回_EINIR。

(3)具體參見linux/kernel/mutex.c

int fastcall __sched mutex_trylock(struct mutex *lock);

試圖獲取互斥鎖,如果成功獲取則返回1,否則返回0,不等待。

釋放互斥鎖

具體參見linux/kernel/mutex.c

void fastcall mutex_unlock(struct mutex *lock);

釋放被當(dāng)前進程獲取的互斥鎖。該函數(shù)不能用在中斷上下文中,而且不允許去釋放一個沒有上鎖的互斥鎖。

信號量和互斥體

互斥體和信號量很相似,內(nèi)核中兩者共存會令人混淆。所幸,它們的標準使用方式都有簡單規(guī)范:除非mutex的某個約束妨礙你使用,否則相比信號量要優(yōu)先使用mutex。當(dāng)你寫新代碼時,只有碰到特殊場合(一般是很底層代碼)才會需要使用信號量。因此建議 選mutex。如果發(fā)現(xiàn)不能滿足其約束條件,且沒有其他別的選擇時,再考慮選擇信號量

自旋鎖和互斥體使用場合

了解何時使用自旋鎖,何時使用互斥體(或信號量)對編寫優(yōu)良代碼很重要,但是多數(shù)情況下,并不需要太多的考慮,因為在中斷上下文中只能使用自旋鎖,而在任務(wù)睡眠時只能使用互斥體。

下面總結(jié)一下各種鎖的需求情況

需求

建議的加鎖方法

低開銷加鎖

優(yōu)先使用自旋鎖

短期鎖定

優(yōu)先使用自旋鎖

長期鎖定

優(yōu)先使用互斥體

中斷上下文中加鎖

使用自旋鎖

持有鎖需要睡眠

使用互斥體

互斥鎖鎖定和解鎖使用實例

使用方法如下:

1. struct mutex mutex;
2. mutex_init(&mutex); /*定義*/
3. //加鎖
4. mutex_lock(&mutex);
5.  
6. //臨界區(qū)
7. 
8. //解鎖
9. mutex_unlock(&mutex);

可以看出,互斥體就是一個簡化版的信號量,因為不再需要管理任何使用計數(shù)。

下面網(wǎng)卡DM9000的驅(qū)動,其中寫入eeprom的操作試用了mutex機制:

static void
dm9000_write_eeprom(board_info_t *db, int offset, u8 *data)
{
 unsigned long flags;

 if (db->flags & DM9000_PLATF_NO_EEPROM)
  return;

 mutex_lock(&db->addr_lock);

 spin_lock_irqsave(&db->lock, flags);
 iow(db, DM9000_EPAR, offset);
 iow(db, DM9000_EPDRH, data[1]);
 iow(db, DM9000_EPDRL, data[0]);
 iow(db, DM9000_EPCR, EPCR_WEP | EPCR_ERPRW);
 spin_unlock_irqrestore(&db->lock, flags);

 dm9000_wait_eeprom(db);

 mdelay(1); /* wait at least 150uS to clear */

 spin_lock_irqsave(&db->lock, flags);
 iow(db, DM9000_EPCR, 0);
 spin_unlock_irqrestore(&db->lock, flags);

 mutex_unlock(&db->addr_lock);
}

可以看到每次驅(qū)動向eeprom寫入數(shù)據(jù)(訪問臨界資源),都需要首先獲得該資源對應(yīng)的互斥鎖db->addr_lock,并且使用完畢必須釋放該鎖。

重要聲明:本文來自一口Linux,經(jīng)授權(quán)轉(zhuǎn)載,版權(quán)歸原作者所有,不代表銳成觀點,轉(zhuǎn)載的目的在于傳遞更多知識和信息。

我的評論

還未登錄?點擊登錄

微信掃碼溝通
微信掃碼溝通

微信掃碼溝通

AI
return head