女人自慰AV免费观看内涵网,日韩国产剧情在线观看网址,神马电影网特片网,最新一级电影欧美,在线观看亚洲欧美日韩,黄色视频在线播放免费观看,ABO涨奶期羡澄,第一导航fulione,美女主播操b

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

信號量實現原理介紹

strongerHuang ? 來源:嵌入式藝術 ? 2024-01-10 09:07 ? 次閱讀

轉自 |嵌入式藝術 除了原子操作,中斷屏蔽,自旋鎖以及自旋鎖的衍生鎖之外,在Linux內核中還存在著一些其他同步互斥的手段。

下面我們來理解一下信號量,互斥體,完成量機制。

1、信號量介紹

信號量(Semaphore)是操作系統中最典型的用于同步和互斥的手段,信號量的值可以是0、1或者n。信號量與操作系統中的經典概念PV操作對應。 P(Produce):

將信號量S的值減1,即S=S-1;

如果S≥0,則該進程繼續執行;否則該進程置為等待狀態,排入等待隊列。

V(Vaporize):

將信號量S的值加1,即S=S+1;

如果S>0,喚醒隊列中等待信號量的進程。

信號量核心思想: 信號量的操作,更適合去解決生產者和消費者的問題,比如:我做出來一個餅,你才能吃一個餅;如果我沒做出來,你就先釋放CPU去忙其他的事情。

2、信號量的API

struct semaphore sem; // 定義信號量

void sema_init(struct semaphore *sem, int val); // 初始化信號量,并設置信號量sem的值為val。

void down(struct semaphore * sem); // 獲得信號量sem,它會導致睡眠,因此不能在中斷上下文中使用。
int down_interruptible(struct semaphore * sem); // 該函數功能與down類似,不同之處為,因為down()進入睡眠狀態的進程不能被信號打斷,但因為down_interruptible()進入睡眠狀態的進程能被信號打斷,信號也會導致該函數返回,這時候函數的返回值非0
int down_trylock(struct semaphore * sem); // 嘗試獲得信號量sem,如果能夠立刻獲得,它就獲得該信號量并返回0,否則,返回非0值。它不會導致調用者睡眠,可以在中斷上下文中使用。

void up(struct semaphore * sem); // 釋放信號量,喚醒等待者。

由于新的Linux內核傾向于直接使用mutex作為互斥手段,信號量用作互斥不再被推薦使用。 信號量也可以用于同步,一個進程A執行down()等待信號量,另外一個進程B執行up()釋放信號量,這樣進程A就同步地等待了進程B。

3、API實現

3.1 semaphore

struct semaphore {
raw_spinlock_t lock;
unsigned int count;
struct list_head wait_list;
};

結構體名稱:semaphore

文件位置:include/linux/semaphore.h

主要作用:用于定義一個信號量。

raw_spinlock_t:信號量結構體也使用了自旋鎖,避免互斥。

count:表示信號量的計數器,表示資源的數量

struct list_head wait_list: 這是一個鏈表頭,用于管理等待信號量的線程。當信號量的 count 等于0,即沒有可用資源時,等待信號量的線程會被加入到這個鏈表中,以便在資源可用時進行喚醒。

3.2 sema_init

static inline void sema_init(struct semaphore *sem, int val)
{
static struct lock_class_key __key;
*sem = (struct semaphore) __SEMAPHORE_INITIALIZER(*sem, val);
lockdep_init_map(&sem->lock.dep_map, "semaphore->lock", &__key, 0);
}

#define __SEMAPHORE_INITIALIZER(name, n)
{
.lock = __RAW_SPIN_LOCK_UNLOCKED((name).lock),
.count = n,
.wait_list = LIST_HEAD_INIT((name).wait_list),
}

#define LIST_HEAD_INIT(name) { &(name), &(name) }

函數名稱:sema_init

文件位置:include/linux/semaphore.h

主要作用:初始化信號量,并設置信號量sem的值為val。

實現流程

使用__SEMAPHORE_INITIALIZER宏定義來初始化信號量

使用__RAW_SPIN_LOCK_UNLOCKED宏定義來初始化自旋鎖

直接將val賦值給信號量的值count

使用LIST_HEAD_INIT來初始化一個鏈表


#defineLIST_HEAD_INIT(name){&(name),&(name)}

該宏接受一個參數 name,并返回一個結構體對象。這個對象有兩個成員 next 和 prev,分別指向 name 本身。

這樣,當我們使用該宏來初始化鏈表頭節點時,會得到一個擁有 next 和 prev 成員的結構體對象。其中 next 和 prev 成員都指向該結構體對象本身。

這種初始化方式可以用于創建一個空的雙向鏈表,因為在初始狀態下,鏈表頭節點的 next 和 prev 指針都指向自身,表示鏈表為空。

3.3 down

/**

down - acquire the semaphore
@sem: the semaphore to be acquired

Acquires the semaphore. If no more tasks are allowed to acquire the
semaphore, calling this function will put the task to sleep until the
semaphore is released.

Use of this function is deprecated, please use down_interruptible() or
down_killable() instead.
*/
void down(struct semaphore *sem)
{
unsigned long flags;

raw_spin_lock_irqsave(&sem->lock, flags);
if (likely(sem->count > 0))
sem->count--;
else
__down(sem);
raw_spin_unlock_irqrestore(&sem->lock, flags);
}
EXPORT_SYMBOL(down);

static noinline void __sched __down(struct semaphore *sem)
{
__down_common(sem, TASK_UNINTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
}

/*

Because this function is inlined, the 'state' parameter will be
constant, and thus optimised away by the compiler. Likewise the
'timeout' parameter for the cases without timeouts.
*/
static inline int __sched __down_common(struct semaphore *sem, long state,
long timeout)
{
struct semaphore_waiter waiter;

list_add_tail(&waiter.list, &sem->wait_list);
waiter.task = current;
waiter.up = false;

for (;;) {
if (signal_pending_state(state, current))
goto interrupted;
if (unlikely(timeout <= 0))
goto timed_out;
__set_current_state(state);
raw_spin_unlock_irq(&sem->lock);
timeout = schedule_timeout(timeout);
raw_spin_lock_irq(&sem->lock);
if (waiter.up)
return 0;
}

timed_out:
list_del(&waiter.list);
return -ETIME;

interrupted:
list_del(&waiter.list);
return -EINTR;
}


函數名稱:down

文件位置:kernel/locking/semaphore.c

主要作用:獲取信號量,如果信號量的值大于0,則消耗一個;如果不存在,則讓線程進入休眠狀態并等待信號量被釋放。

函數調用流程


down(kernel/locking/semaphore.c)
|--> raw_spin_lock_irqsave // 獲取鎖,并保存中斷信息
||-> sem->count--; // 如果sem->count信號量存在,則消耗一個
|-> __down // 如果sem->count信號量不存在,則進入休眠狀態
|--> __down_common
|--> list_add_tail // 將當前線程添加到信號量的等待鏈表中,表示當前線程正在等待信號量。
|--> __set_current_state// 設置線程為休眠狀態
|--> raw_spin_unlock_irq// 釋放自旋鎖,讓其他線程可用
|--> schedule_timeout // 讓線程進入睡眠狀態,等待信號量釋放或超時。
|--> raw_spin_lock_irq // 重新獲取自旋鎖,繼續執行后續操作
|--> raw_spin_unlock_irqrestore // 釋放鎖,并恢復中斷信息

實現流程

獲取信號量時,先使用raw_spin_lock_irqsave和raw_spin_unlock_irqrestore將信號量的操作包裹起來,避免競態發生。

然后對sem->count判斷,如果信號量大于0,就消耗一個,否則的話,將當前線程設置為休眠態

調用__down_common接口,默認將當前線程設置為TASK_UNINTERRUPTIBLE中斷不可打斷狀態,并設置最大超時時間MAX_SCHEDULE_TIMEOUT

struct semaphore_waiter waiter:創建waiter結構體,表示當前線程的狀態

調用__set_current_state接口,設置當前線程的狀態信息,即TASK_UNINTERRUPTIBLE

調用schedule_timeout,讓該線程讓出CPU,進入休眠態,并且在前面加上raw_spin_unlock_irq保證其他線程可以正常使用信號量。

當線程時間片到時,獲取CPU,并調用raw_spin_lock_irq,獲取鎖,來防止競態發生。

3.4 up

/**

up - release the semaphore
@sem: the semaphore to release
Release the semaphore. Unlike mutexes, up() may be called from any
context and even by tasks which have never called down().
*/
void up(struct semaphore *sem)
{
unsigned long flags;

raw_spin_lock_irqsave(&sem->lock, flags);
if (likely(list_empty(&sem->wait_list)))
sem->count++;
else
__up(sem);
raw_spin_unlock_irqrestore(&sem->lock, flags);
}
EXPORT_SYMBOL(up);

static noinline void __sched __up(struct semaphore *sem)
{
struct semaphore_waiter *waiter = list_first_entry(&sem->wait_list,
struct semaphore_waiter, list);
list_del(&waiter->list);
waiter->up = true;
wake_up_process(waiter->task);
}


函數名稱:up

文件位置:kernel/locking/semaphore.c

主要作用:獲取信號量,如果信號量的值大于0,則消耗一個;如果不存在,則讓線程進入休眠狀態并等待信號量被釋放。

實現流程

相信分析完down后,up也變得很簡單

釋放信號量時,先使用raw_spin_lock_irqsave和raw_spin_unlock_irqrestore將信號量的操作包裹起來,避免競態發生。

然后對sem->wait_list判斷,如果其為空,說明沒有等待的線程,直接將sem->count自增,如果有等待的線程,則喚醒下一個線程。

調用wake_up_process來喚醒線程

4、總結

信號量較為簡單,一般常用來解決生產者和消費者的問題,其主要還是通過自旋鎖來實現互斥的作用,通過鏈表來管理等待隊列的線程信息,通過變量來代表資源的數量。






審核編輯:劉清

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 計數器
    +關注

    關注

    32

    文章

    2284

    瀏覽量

    96021
  • LINUX內核
    +關注

    關注

    1

    文章

    317

    瀏覽量

    22176
  • 信號量
    +關注

    關注

    0

    文章

    53

    瀏覽量

    8499
  • 自旋鎖
    +關注

    關注

    0

    文章

    11

    瀏覽量

    1657

原文標題:信號量實現原理

文章出處:【微信號:strongerHuang,微信公眾號:strongerHuang】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦
    熱點推薦

    FreeRTOS信號量使用教程

    信號量是操作系統中重要的一部分,信號量一般用來進行資源管理和任務同步, FreeRTOS中信號量又分為二值信號量、 計數型信號量、互斥
    的頭像 發表于 12-19 09:22 ?3742次閱讀
    FreeRTOS<b class='flag-5'>信號量</b>使用教程

    信號量是什么?信號量怎么運作

    信號量信號量簡介二值信號量計數信號量應用場景二值信號量怎么運作計數信號量怎么運作
    發表于 01-05 08:09

    如何用VxWorks的信號量機制實現任務同步

    如何用VxWorks的信號量機制實現任務同步
    發表于 03-29 12:25 ?16次下載

    簡單介紹信號信號量

    信號量實際上是一種約定機制,在多任務內核中普遍使用。信號量用于:控制共享資源的使用權(滿足互斥條件)標志某事件的發生使兩個任務的行為同步。
    的頭像 發表于 05-25 10:14 ?9914次閱讀
    簡單<b class='flag-5'>介紹信號</b>與<b class='flag-5'>信號量</b>

    你了解Linux 各類信號量

    內核信號量與用戶信號量,用戶信號量分為POXIS信號量和SYSTEMV信號量,POXIS信號量
    發表于 05-04 17:19 ?2636次閱讀
    你了解Linux 各類<b class='flag-5'>信號量</b>?

    uCOS信號量源碼的詳細資料分析

    本文檔的主要內容詳細介紹的是uCOS信號量源碼的詳細資料分析。 信號量相關的函數 創建一個信號量,參數是信號量的初始值,創建成功返回值是
    發表于 06-17 17:38 ?7次下載
    uCOS<b class='flag-5'>信號量</b>源碼的詳細資料分析

    詳解互斥信號量的概念和運行

    1 、互 斥 信 號 1.1 互斥信號量的概念及其作用 互斥信號量的主要作用是對資源實現互斥訪問,使用二值信號量也可以
    的頭像 發表于 10-22 11:57 ?1.2w次閱讀
    詳解互斥<b class='flag-5'>信號量</b>的概念和運行

    Linux信號量(2):POSIX 信號量

    上一章,講述了 SYSTEM V 信號量,主要運行于進程之間,本章主要介紹 POSIX 信號量:有名信號量、無名信號量。 POSIX
    的頭像 發表于 10-29 17:34 ?888次閱讀

    LINUX內核的信號量設計與實現

    控制路徑可以睡眠。我們從 LINUX內核信號量最直觀的設計/實現出發,通過一步步改進,揭示在x86平臺上完整的信號量設計/實現,然后探討在不同平臺上通用的
    發表于 01-14 16:55 ?18次下載

    LINUX內核的信號量設計與實現

    控制路徑可以睡眠。我們從 LINUX內核信號量最直觀的設計/實現出發,通過一步步改進,揭示在x86平臺上完整的信號量設計/實現,然后探討在不同平臺上通用的
    發表于 01-14 16:55 ?5次下載

    FreeRTOS的二值信號量

    FreeRTOS中的信號量是一種任務間通信的方式,信號量包括:二值信號量、互斥信號量、計數信號量,本次實驗只使用二值
    的頭像 發表于 02-10 15:07 ?1697次閱讀

    Free RTOS的計數型信號量

    上篇講解了二值信號量,二值信號量只能判斷有無,而不能確定事件發生的次數,因此我們為了確定事件的次數引入了計數型信號量
    的頭像 發表于 02-10 15:29 ?1244次閱讀
    Free RTOS的計數型<b class='flag-5'>信號量</b>

    使用Linux信號量實現互斥點燈

    信號量常用于控制對共享資源的訪問,有計數型信號量和二值信號量之分。初始化時信號量值大于1的,就是計數型信號量,計數型
    的頭像 發表于 04-13 15:12 ?1005次閱讀
    使用Linux<b class='flag-5'>信號量</b><b class='flag-5'>實現</b>互斥點燈

    FreeRTOS四種信號量詳細介紹

    1、二值信號量 二值信號量通常用于互斥訪問或同步,二值信號量和互斥信號量非常類似,但是還是有一些細微的差別,互斥信號量擁有優先級繼承機制,二
    的頭像 發表于 07-06 17:14 ?3090次閱讀

    Semaphore信號量概念及其介紹

    信號量即Semaphore。信號量主要用于控制和保護任務對特定資源的訪問。
    的頭像 發表于 07-25 15:40 ?2195次閱讀
    Semaphore<b class='flag-5'>信號量</b>概念及其<b class='flag-5'>介紹</b>