訊號量也是一種保護臨界資源的一種方法。訊號量與自旋鎖的使用方法基本一樣。與與自旋鎖不同的是,當獲取不到訊號量時,程序不會原地打轉而是進入休眠等待狀態。
在linux中,訊號量的定義如下
struct semaphore
成員變數
1. lock自旋鎖
對count變數起保護作用
2. count變數
是訊號量中乙個非常重要的成員,可能有下面3種值
(1) 等於0的值:如果這個值等於0,表示訊號量被其他程序使用,現在不可以使用這個訊號量,但是在wait_list佇列中沒有程序等待訊號量。
(2) 小於0的值:如果這個值小於0,那麼表示至少有乙個程序在wait_list佇列中等待訊號量的釋放。
(3)大於0的值:如果這個值大於0,表示這個訊號量是空閒的,程式可以使用這個訊號量。
從此看出與自旋鎖的一點不同是,自旋鎖只能允許乙個程序持有自旋鎖,而訊號量可以根據count的值,設定有多少個程序持有這個訊號量。根據count的取值,可以將訊號量分為二值訊號量和計數訊號量。
二值訊號量,就是count初始化時,被設定成1時的使用量,這種型別的訊號量可以強制二者同一時刻只有乙個執行。
計數訊號量,允許乙個時刻有乙個或者多個程序同時持有訊號量。具體個數取決於count的取值
等待佇列
wait 是乙個等待佇列的煉表頭,這個鍊錶將所有等待該訊號量的程序組成乙個鍊錶結構,在這個鍊錶中,存放了正在睡眠的程序鍊錶
核心提供了一系列函式對semaphore進行操作
1.定義和初始化自旋鎖
struct semaphore sema;訊號量必須初始化後才能被使用,sema_init()函式用來初始化訊號量,並設定sem中的count的值為val,函式原型為
static
inline
void sema_init(struct semaphore *sem,int val)
相關初始化方法
void init_mutex(struct semaphore *sem);
該函式用於初始化乙個用於互斥的訊號量,它把訊號量 sem 的值設定為 1,等同於sema_init (struct semaphore *sem, 1)。
void init_mutex_locked (struct semaphore *sem);
該函式也用於初始化乙個訊號量,但它把訊號量 sem 的值設定為 0,等同於sema_init (struct semaphore *sem, 0)。
此外,下面兩個巨集是定義並初始化訊號量的「快捷方式」。
declare_mutex(name)
declare_mutex_locked(name)
前者定義乙個名為 name 的訊號量並初始化為 1,後者定義乙個名為 name 的訊號量並初始化為 0。
2. 鎖定訊號量
進入臨界區前,使用down()函式獲得訊號量
void down(struct semaphore *sem);
該函式會導致睡眠,不能在中斷上下文中使用
另乙個函式與down()函式相似
int down_interrupttible(struct semaphore *sem);
此函式進入睡眠後可以被訊號喚醒,如果被訊號喚醒,返回非0值,在呼叫down_interruptible()函式時,一般會檢查返回值,判斷被喚醒的原因
if (down_interruptible(&sem))
如果非 0,通常立即返回-erestartsys
3. 釋放訊號量
void up(struct semaphore *sem);
4.使用訊號量
定義訊號量->初始化->獲得訊號量->釋放訊號量
struct semaphore sem;
int ***_init(void)
//檔案開啟函式
int ***_open(struct inode *inode,strct file *filp)
//檔案分釋放函式
int ***_release(struct inode *inode,strct file *filp)
5.訊號量用於同步
如果訊號量被初始化為 0,則它可以用於同步,同步意味著乙個執行單元的繼續執行需等待另一執行單元完成某事,保證執行的先後順序。如下圖所示,執行緒a執行到被保護**a之前,一直處於睡眠狀態,直到執行緒b執行完被保護**b並呼叫up()函式後,才會執行被保護**a。
自旋鎖只是進行忙等待,不會休眠,訊號量用於多個程序之間互斥時可能引起程序的睡眠,所以只有在乙個程序對被保護的資源占用時間比程序切換時間長很多時,訊號量才是乙個更好的選擇,否則會降低系統執行效率
一種linux中的機制,用於實現乙個執行緒傳送乙個訊號通知另乙個執行緒並開始執行完某個任務。
linux中完成量用 struct completion 結構體表示,定義在 include\linux\completion.h中
struct completion;
1.定義和初始化
struct completion com;
乙個完成量必須初始化才能被使用,init_completion()
static
inline
void init_completion(struct completion *x)
也可以使用巨集 declare_completion 定義和初始化乙個完成量
#define declare_completion(work) \
struct completion work = completion_initializer(work)
#define completion_initializer(work) \
2.等待完成量
使用wait_for_completion()函式等待乙個完成量
void __sched wait_for_completion(struct completion *x)
呼叫這個函式以後,沒有乙個執行緒完成這個完成量,那麼執行wait_for_completion()函式的執行緒會一直等待下去,執行緒將不可以退出
3.釋放完成量
當需要同步的任務完成後,可以使用下面的兩個函式喚醒完成量。
兩個函式定義如下
void complete(struct completion *x)
void complete_all(struct completion *x)
前者只喚醒乙個等待的程序或者執行緒,後者將喚醒所有等待的程序或者執行緒。
4.使用完成量
定義、初始化、獲得、釋放
struct completion com;
int ***_init(void)
int ***_a()
int ***_b()
Linux 裝置驅動中的併發控制
是指作業系統中,乙個時間段中有幾個程式都處於啟動執行到執行完畢間,且這幾個程式都是同乙個處理器上執行,但任何乙個時間點只有乙個程式在處理機器上執行。併發容易導致競爭問題。是兩個或者多個程序同時訪問乙個資源,從而引起的資源錯誤。所謂的原子操作就是該作業系統不會在執行完畢前被任何其他任務或者事件打斷。也...
Linux 裝置驅動併發控制簡述
答案 在linux中會遇到多個程序對共享資源的併發訪問,併發訪問會導致競態的發生,所以需要併發控制機制。併發與競態是指多個執行單位同時並行的被執行,而併發的執行單位對共享資源的訪問很容易導致競態 2.1 對稱多處理器 smp系統 的多個cpu 多個cpu共用同一條系統匯流排,因此可以訪問共同的外設和...
Linux 裝置驅動併發控制例項
在前面的筆記中,學習了linux裝置驅動中的併發控制,其中有中斷遮蔽 原子操作 自旋鎖 訊號量 互斥體及完成量。這幾種併發控制的技術就是解決多程序或多cpu之間對共享資源的同時訪問引起的競態問題。它們之間根據各自的性質使用在不同的場合中,這裡就不重複的介紹了,下面來分析 linux裝置驅動開發詳解 ...