訊號量(semaphore
)是用於保護臨界區的一種常用方法。只有得到訊號量的程序才能執行臨界區**,而沒有得到訊號量的程序進入休眠等待狀態。
linux
系統中與訊號量相關的操作主要有如下4種。
1 定義訊號量
下面**定義名為
sem的訊號量。
struct semaphore sem;
struct semaohore
結構體在核心中定義如下:
在/include/linux/semaphore.h
目錄下:
struct semaphore;
2初始化訊號量
在/include/linux/semaphore.h
目錄下,
void sema_init(struct semaphore*
sem, int val)
函式用於初始化訊號量,並設定訊號量
sem的值為
val。儘管訊號量可以被初始化為大於
1的值從而成為乙個計數訊號量,但是它通常不被這樣使用。
核心定義了兩個巨集來把
sem的值設定為1或者
0。#define init_mutex(sem)sema_init(sem, 1)
#define init_mutex_locked(sem)sema_init(sem, 0)
使用init_mutex(sem)
初始化訊號量時,表示訊號量最初是可以被獲取的。而使用
init_mutex_locked(sem)
初始化訊號量時,此訊號量只有先被釋放才可以獲取。
3獲取訊號量
void down(struct semaphore *sem);
該函式用於獲取訊號量
sem,它會導致睡眠,因此不能在中斷上下文使用。
在核心裡該函式的源**如下:
在kernel/semaphore.c
檔案裡:
53 void down(struct semaphore *sem)
54
這裡重點看
58行:
if (likely(sem->count > 0))
,這句話表示當獲取訊號量成功時,就執行
sem->count—;
即對訊號量的值減一。
else
表示獲取訊號量失敗,此時呼叫
__down
函式進入睡眠狀態,並將此程序插入到等待佇列尾部。
核心定義了訊號量的等待佇列結構體:
193 struct semaphore_waiter ;
此結構體是乙個雙向迴圈鍊錶。
int down_interruptible(struct semaphore *sem);
該函式功能與
down()
類似,不同之處是,
down()
在獲取訊號量失敗進入睡眠狀態時的程序是不能被打斷的,而
down_interruptible()
在進入睡眠狀態時的程序能被訊號打斷,訊號也會導致函式返回。下面我們也來看一看這個函式的原始碼:
在kernel/semaphore.c
檔案裡:
75 int down_interruptible(struct semaphore *sem)
76
這裡我們可以看到,當獲取訊號量成功時,返回
0,而獲取訊號量失敗時,返回乙個非
0的值。在使用
down_interruptible()
函式獲取訊號量時,對返回值一般會進行檢查,如果非
0,通常立即返回
-erestartsys
。如:if ( down_interruptible(&sem) )
return -erestartsys;
這裡還有乙個問題:在獲取訊號量失敗後,為什麼
down
不能被中斷,而
down_interruptible
卻可以被中斷呢?我們從
down
和down_interruptible
的源**可以得知,在獲取訊號量失敗後,
down
函式執行了
__down
函式,而
down_interruptible
函式執行了
__down_interruptible
。那麼讓我們來看一下這兩個函式的原始碼:
在kernel/semaphore.c
檔案裡:
236 static noinline void __sched __down(struct semaphore *sem)
237
240
241 static noinline int __sched __down_interruptible(struct semaphore *sem)
242
在__down
函式裡,是把程序的狀態設定為
task_uninterruptible
,即不可中斷狀態。
而在__down_interruptible
裡,是把程序的狀態設定為
task_interruptible
,即可中斷狀態。這就解釋了以上提出的問題。
4釋放訊號量
void up(struct semaphore *sem);
該函式用於釋放訊號量
sem,
喚醒等待者。
它的源**如下:
178 void up(struct semaphore *sem)
179 ,
};int thread_one(void *p);
int thread_two(void *p);
int thread_one(void *p)
return 0; }
int thread_two(void *p)
return 0; }
static int lan_init(void)
static void lan_exit(void)
module_init(lan_init);
module_exit(lan_exit);
0 給主人留下些什麼吧!~~
Linux核心 訊號量
linux訊號量是一種睡眠鎖。如果有乙個任務試圖獲得乙個不可用 已經被占用 的訊號量時,訊號量會將其推入乙個等待佇列,然後讓其睡眠。這時處理器可以重獲自由,從而去執行其他 當持有的訊號量可用 被釋放 後,處於等待佇列中的那個任務被喚醒,並獲得該訊號量。舉例說明 當某個人來到門前,他抓取鑰匙,進入房間...
核心 訊號量
核心訊號量和自旋鎖類似,作用也是保護資料。不同之處是,程序獲取核心訊號量嘚瑟時候,如果不能獲取,則程序進入睡眠狀態。down dev sem up dev sem 核心訊號量和自旋鎖的不同 1 核心訊號量 不能用在 中斷處理函式 和 tasklet 等不可睡眠的場景 2 深層次的原因 linux核心...
linux核心同步 4 訊號量
任務獲取乙個已經被占用的訊號量,訊號量將其推進乙個等待佇列,然後讓其睡眠,cpu 去執行其他 當持有訊號量的程序將訊號釋放,處於等待佇列彙總的任務被喚醒,並獲取訊號量。訊號量會引起睡眠,所以在中斷上下文中不能使用訊號量。一般在程序上下文中使用。乙個程序占用訊號量的同時不能同時占用自旋鎖,因為占用訊號...