linux同步機制之訊號量down 和up

2021-08-03 14:27:16 字數 3608 閱讀 6662

linux核心的訊號量在概念和原理上和使用者態的system v的ipc機制訊號量是相同的,不過他絕不可能在核心之外使用,因此他和system v的ipc機制訊號量毫不相干。

訊號量在建立時需要設定乙個初始值,表示同時能有幾個任務能訪問該訊號量保護的共享資源,初始值為1就變成互斥鎖(mutex),即同時只能有乙個任務能訪問訊號量保護的共享資源。

乙個任務要想訪問共享資源,首先必須得到訊號量,獲取訊號量的操作將把訊號量的值減1,若當前訊號量的值為負數,表明無法獲得訊號量,該任務必須掛起在 該訊號量的等待佇列等待該訊號量可用;若當前訊號量的值為非負數,表示能獲得訊號量,因而能即時訪問被該訊號量保護的共享資源。

當任務訪問完被訊號量保護的共享資源後,必須釋放訊號量,釋放訊號量通過把訊號量的值加1實現,如果訊號量的值為非正數,表明有任務等待當前訊號量,因此他也喚醒所有等待該訊號量的任務。

訊號量的api有:

declare_mutex(name)

該巨集宣告乙個訊號量name並初始化他的值為1,即宣告乙個互斥鎖。

declare_mutex_locked(name)

該巨集宣告乙個互斥鎖name,但把他的初始值設定為0,即鎖在建立時就處在已鎖狀態。因此對於這種鎖,一般是先釋放後獲得。

void sema_init (struct semaphore *sem, int val);

該函用於數初始化設定訊號量的初值,他設定訊號量sem的值為val。

void init_mutex (struct semaphore *sem);

該函式用於初始化乙個互斥鎖,即他把訊號量sem的值設定為1。

void init_mutex_locked (struct semaphore *sem);

該函式也用於初始化乙個互斥鎖,但他把訊號量sem的值設定為0,即一開始就處在已鎖狀態。

void down(struct semaphore * sem);

該函式用於獲得訊號量sem,他會導致睡眠,因此不能在中斷上下文(包括irq上下文和softirq上下文)使用該函式。該函式將把sem的值減1,如果訊號量sem的值非負,就直接返回,否則呼叫者將被掛起,直到別的任務釋放該訊號量才能繼續執行。

int down_interruptible(struct semaphore * sem);

該函式功能和down類似,不同之處為,down不會被訊號(signal)打斷,但down_interruptible能被訊號打斷,因此該函式有返回值來區分是正常返回還是被訊號中斷,如果返回0,表示獲得訊號量正常返回,如果被訊號打斷,返回-eintr。

int down_trylock(struct semaphore * sem);

該函式試著獲得訊號量sem,如果能夠即時獲得,他就獲得該訊號量並返回0,否則,表示不能獲得訊號量sem,返回值為非0值。因此,他不會導致呼叫者睡眠,能在中斷上下文使用。

int down_killable(struct semaphore *sem);

int down_timeout(struct semaphore *sem, long jiffies);

int down_timeout_interruptible(struct semaphore *sem, long jiffies);

void up(struct semaphore * sem); 

該函式釋放訊號量sem,即把sem的值加1,如果sem的值為非正數,表明有任務等待該訊號量,因此喚醒這些等待者。

訊號量在絕大部分情況下作為互斥鎖使用,下面以console驅動系統為例說明訊號量的使用。 

在核心原始碼樹的kernel/printk.c中,使用巨集declare_mutex宣告了乙個互斥鎖console_sem,他用於保護console驅動列表console_drivers及同步對整個console驅動系統的訪問。 

其中定義了函式acquire_console_sem來獲得互斥鎖console_sem,定義了release_console_sem來釋放互斥 鎖console_sem,定義了函式try_acquire_console_sem來盡力得到互斥鎖console_sem。這三個函式實際上是分別 對函式down,up和down_trylock的簡單包裝。 

需要訪問console_drivers驅動列表時就需要使用acquire_console_sem來保護console_drivers列表,當訪問完該列表後,就呼叫release_console_sem釋放訊號量console_sem。 

函式 console_unblank,console_device,console_stop,console_start,register_console 和unregister_console都需要訪問console_drivers,因此他們都使用函式對acquire_console_sem和 release_console_sem來對console_drivers進行保護。

int down_interruptible(struct semaphore *sem)

這個函式的功能就是獲得訊號量,如果得不到訊號量就睡眠,此時沒有訊號打斷,那麼進入睡眠。但是在睡眠過程中可能被訊號打斷,打斷之後返回-eintr,主要用來程序間的互斥同步。

下面是該函式的注釋:

/*** down_interruptible - acquire the semaphore unless interrupted

* @sem: the semaphore to be acquired

** attempts to acquire the semaphore. if no more tasks are allowed to

* acquire the semaphore, calling this function will put the task to sleep.

* if the sleep is interrupted by a signal, this function will return -eintr.

* if the semaphore is successfully acquired, this function returns 0.

*/乙個程序在呼叫down_interruptible()之後,如果sem<0,那麼就進入到可中斷的睡眠狀態並排程其它程序執行, 但是一旦該程序收到訊號,那麼就會從down_interruptible函式中返回。並標記錯誤號為:-eintr。乙個形象的比喻:傳入的訊號量為1好比天亮,如果當前訊號量為0,程序睡眠,直到(訊號量為1)天亮才醒,但是可能中途有個鬧鈴(訊號)把你鬧醒。又如:小強下午放學回家,回家了就要開始吃飯嘛,這時就會有兩種情況:情況一:飯做好了,可以開始吃;情況二:當他到廚房去的時候發現媽媽還在做,媽媽就對他說:「你先去睡會,待會做好了叫你。」小強就答應去睡會,不過又說了一句:「睡的這段時間要是小紅來找我玩,你可以叫醒我。」小強就是down_interruptible,想吃飯就是獲取訊號量,睡覺對應這裡的休眠,而小紅來找我玩就是中斷休眠。

使用可被中斷的訊號量版本的意思是,萬一出現了semaphore的死鎖,還有機會用ctrl+c發出軟中斷,讓等待這個核心驅動返回的使用者態程序退出。而不是把整個系統都鎖住了。在休眠時,能被中斷訊號終止,這個程序是可以接受中斷訊號的!比如你在命令列中輸入# sleep 10000,按下ctrl + c,就給上面的程序傳送了程序終止訊號。訊號傳送給使用者空間,然後通過系統呼叫,會把這個訊號傳給遞給驅動。訊號只能傳送給使用者空間,無權直接傳送給核心的,那1g的核心空間,我們是無法直接去操作的。

linux核心同步機制之訊號量

定義 如果有乙個任務試圖獲得已經被占用的訊號量時,訊號量會將其推進乙個等待佇列,使其睡眠,當持有訊號量的程序將訊號量釋放以後,再喚醒該任務,並獲得該訊號量。標頭檔案head.h ifndef head h define head h include include include include e...

執行緒同步機制之訊號量

一 什麼是訊號量 執行緒的訊號量與程序間通訊中使用的訊號量的概念是一樣,它是一種特殊的變數,它可以被增加或減少,但對其的關鍵訪問被保證是原子操作。如果乙個程式中有多個執行緒試圖改變乙個訊號量的值,系統將保證所有的操作都將依次進行。而只有0和1兩種取值的訊號量叫做二進位制訊號量,在這裡將重點介紹。而訊...

Linux多執行緒程式設計入門 同步機制 訊號量

int sem init sem t sem,int pshared,unsigned int value pshared 控制訊號量的型別,0表示這個訊號量是當前程序的區域性訊號量,否則,這個訊號量就可以在多個程序之間共享。value 訊號量的初始值。int sem post sem t sem ...