色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

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

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

3天內不再提示

韋東山freeRTOS系列教程之信號量(6)

嵌入式Linux那些事 ? 2021-12-13 14:35 ? 次閱讀

文章目錄

  • 系列教程總目錄
  • 概述
  • 6.1 信號量的特性
    • 6.1.1 信號量的常規操作
    • 6.1.2 信號量跟隊列的對比
    • 6.1.3 兩種信號量的對比
  • 6.2 信號量函數
    • 6.2.1 創建
    • 6.2.2 刪除
    • 6.2.3 give/take
  • 6.3 示例12: 使用二進制信號量來同步
  • 6.4 示例13: 防止數據丟失
  • 6.5 示例14: 使用計數型信號量

需要獲取更好閱讀體驗的同學,請訪問我專門設立的站點查看,地址:http://rtos.100ask.net/

系列教程總目錄

本教程連載中,篇章會比較多,為方便同學們閱讀,點擊這里可以查看文章的 目錄列表,目錄列表頁面地址:https://blog.csdn.net/thisway_diy/article/details/121399484

概述

前面介紹的隊列(queue)可以用于傳輸數據:在任務之間、任務和中斷之間。

有時候我們只需要傳遞狀態,并不需要傳遞具體的信息,比如:

  • 我的事做完了,通知一下你
  • 賣包子了、賣包子了,做好了1個包子!做好了2個包子!做好了3個包子!
  • 這個停車位我占了,你們只能等著

在這種情況下我們可以使用信號量(semaphore),它更節省內存。

本章涉及如下內容:

  • 怎么創建、刪除信號量
  • 怎么發送、獲得信號量
  • 什么是計數型信號量?什么是二進制信號量?

6.1 信號量的特性

6.1.1 信號量的常規操作

信號量這個名字很恰當:

  • 信號:起通知作用
  • 量:還可以用來表示資源的數量
    • 當"量"沒有限制時,它就是"計數型信號量"(Counting Semaphores)
    • 當"量"只有0、1兩個取值時,它就是"二進制信號量"(Binary Semaphores)
  • 支持的動作:"give"給出資源,計數值加1;"take"獲得資源,計數值減1

計數型信號量的典型場景是:

  • 計數:事件產生時"give"信號量,讓計數值加1;處理事件時要先"take"信號量,就是獲得信號量,讓計數值減1。
  • 資源管理:要想訪問資源需要先"take"信號量,讓計數值減1;用完資源后"give"信號量,讓計數值加1。

信號量的"give"、"take"雙方并不需要相同,可以用于生產者-消費者場合:

  • 生產者為任務A、B,消費者為任務C、D
  • 一開始信號量的計數值為0,如果任務C、D想獲得信號量,會有兩種結果:
    • 阻塞:買不到東西咱就等等吧,可以定個鬧鐘(超時時間)
    • 即刻返回失敗:不等
  • 任務A、B可以生產資源,就是讓信號量的計數值增加1,并且把等待這個資源的顧客喚醒
  • 喚醒誰?誰優先級高就喚醒誰,如果大家優先級一樣就喚醒等待時間最長的人

二進制信號量跟計數型的唯一差別,就是計數值的最大值被限定為1。

在這里插入圖片描述

6.1.2 信號量跟隊列的對比

差異列表如下:

隊列 信號量
可以容納多個數據,
創建隊列時有2部分內存: 隊列結構體、存儲數據的空間
只有計數值,無法容納其他數據。
創建信號量時,只需要分配信號量結構體
生產者:沒有空間存入數據時可以阻塞 生產者:用于不阻塞,計數值已經達到最大時返回失敗
消費者:沒有數據時可以阻塞 消費者:沒有資源時可以阻塞

6.1.3 兩種信號量的對比

信號量的計數值都有限制:限定了最大值。如果最大值被限定為1,那么它就是二進制信號量;如果最大值不是1,它就是計數型信號量。

差別列表如下:

二進制信號量 技術型信號量
被創建時初始值為0 被創建時初始值可以設定
其他操作是一樣的 其他操作是一樣的

6.2 信號量函數

使用信號量時,先創建、然后去添加資源、獲得資源。使用句柄來表示一個信號量。

6.2.1 創建

使用信號量之前,要先創建,得到一個句柄;使用信號量時,要使用句柄來表明使用哪個信號量。

對于二進制信號量、計數型信號量,它們的創建函數不一樣:

二進制信號量 計數型信號量
動態創建 xSemaphoreCreateBinary
計數值初始值為0
xSemaphoreCreateCounting
vSemaphoreCreateBinary(過時了)
計數值初始值為1
靜態創建 xSemaphoreCreateBinaryStatic xSemaphoreCreateCountingStatic

創建二進制信號量的函數原型如下:

/* 創建一個二進制信號量,返回它的句柄。
 * 此函數內部會分配信號量結構體 
 * 返回值: 返回句柄,非NULL表示成功
 */
SemaphoreHandle_t xSemaphoreCreateBinary( void );

/* 創建一個二進制信號量,返回它的句柄。
 * 此函數無需動態分配內存,所以需要先有一個StaticSemaphore_t結構體,并傳入它的指針
 * 返回值: 返回句柄,非NULL表示成功
 */
SemaphoreHandle_t xSemaphoreCreateBinaryStatic( StaticSemaphore_t *pxSemaphoreBuffer );

創建計數型信號量的函數原型如下:

/* 創建一個計數型信號量,返回它的句柄。
 * 此函數內部會分配信號量結構體 
 * uxMaxCount: 最大計數值
 * uxInitialCount: 初始計數值
 * 返回值: 返回句柄,非NULL表示成功
 */
SemaphoreHandle_t xSemaphoreCreateCounting(UBaseType_t uxMaxCount, UBaseType_t uxInitialCount);

/* 創建一個計數型信號量,返回它的句柄。
 * 此函數無需動態分配內存,所以需要先有一個StaticSemaphore_t結構體,并傳入它的指針
 * uxMaxCount: 最大計數值
 * uxInitialCount: 初始計數值
 * pxSemaphoreBuffer: StaticSemaphore_t結構體指針
 * 返回值: 返回句柄,非NULL表示成功
 */
SemaphoreHandle_t xSemaphoreCreateCountingStatic( UBaseType_t uxMaxCount, 
                                                 UBaseType_t uxInitialCount, 
                                                 StaticSemaphore_t *pxSemaphoreBuffer );

6.2.2 刪除

對于動態創建的信號量,不再需要它們時,可以刪除它們以回收內存。

vSemaphoreDelete可以用來刪除二進制信號量、計數型信號量,函數原型如下:

/*
 * xSemaphore: 信號量句柄,你要刪除哪個信號量
 */
void vSemaphoreDelete( SemaphoreHandle_t xSemaphore );

6.2.3 give/take

二進制信號量、計數型信號量的give、take操作函數是一樣的。這些函數也分為2個版本:給任務使用,給ISR使用。列表如下:

在任務中使用 在ISR中使用
give xSemaphoreGive xSemaphoreGiveFromISR
take xSemaphoreTake xSemaphoreTakeFromISR

xSemaphoreGive的函數原型如下:

BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore );

xSemaphoreGive函數的參數與返回值列表如下:

參數 說明
xSemaphore 信號量句柄,釋放哪個信號量
返回值 pdTRUE表示成功,
如果二進制信號量的計數值已經是1,再次調用此函數則返回失敗;
如果計數型信號量的計數值已經是最大值,再次調用此函數則返回失敗

pxHigherPriorityTaskWoken的函數原型如下:

BaseType_t xSemaphoreGiveFromISR(
                        SemaphoreHandle_t xSemaphore,
                        BaseType_t *pxHigherPriorityTaskWoken
                    );

xSemaphoreGiveFromISR函數的參數與返回值列表如下:

參數 說明
xSemaphore 信號量句柄,釋放哪個信號量
pxHigherPriorityTaskWoken 如果釋放信號量導致更高優先級的任務變為了就緒態,
則*pxHigherPriorityTaskWoken = pdTRUE
返回值 pdTRUE表示成功,
如果二進制信號量的計數值已經是1,再次調用此函數則返回失?。?br /> 如果計數型信號量的計數值已經是最大值,再次調用此函數則返回失敗

xSemaphoreTake的函數原型如下:

BaseType_t xSemaphoreTake(
                   SemaphoreHandle_t xSemaphore,
                   TickType_t xTicksToWait
               );

xSemaphoreTake函數的參數與返回值列表如下:

參數 說明
xSemaphore 信號量句柄,獲取哪個信號量
xTicksToWait 如果無法馬上獲得信號量,阻塞一會:
0:不阻塞,馬上返回
portMAX_DELAY: 一直阻塞直到成功
其他值: 阻塞的Tick個數,可以使用pdMS_TO_TICKS()來指定阻塞時間為若干ms
返回值 pdTRUE表示成功

xSemaphoreTakeFromISR的函數原型如下:

BaseType_t xSemaphoreTakeFromISR(
                        SemaphoreHandle_t xSemaphore,
                        BaseType_t *pxHigherPriorityTaskWoken
                    );

xSemaphoreTakeFromISR函數的參數與返回值列表如下:

參數 說明
xSemaphore 信號量句柄,獲取哪個信號量
pxHigherPriorityTaskWoken 如果獲取信號量導致更高優先級的任務變為了就緒態,
則*pxHigherPriorityTaskWoken = pdTRUE
返回值 pdTRUE表示成功

6.3 示例12: 使用二進制信號量來同步

本節代碼為: FreeRTOS_12_semaphore_binary 。

main函數中創建了一個二進制信號量,然后創建2個任務:一個用于釋放信號量,另一個用于獲取信號量,代碼如下:

/* 二進制信號量句柄 */
SemaphoreHandle_t xBinarySemaphore;

int main( void )
{
	prvSetupHardware();
	
    /* 創建二進制信號量 */
    xBinarySemaphore = xSemaphoreCreateBinary( );

	if( xBinarySemaphore != NULL )
	{
		/* 創建1個任務用于釋放信號量
		 * 優先級為2
		 */
		xTaskCreate( vSenderTask, "Sender", 1000, NULL, 2, NULL );

		/* 創建1個任務用于獲取信號量
		 * 優先級為1
		 */
		xTaskCreate( vReceiverTask, "Receiver", 1000, NULL, 1, NULL );

		/* 啟動調度器 */
		vTaskStartScheduler();
	}
	else
	{
		/* 無法創建二進制信號量 */
	}

	/* 如果程序運行到了這里就表示出錯了, 一般是內存不足 */
	return 0;
}

發送任務、接收任務的代碼和執行流程如下:

  • A:發送任務優先級高,先執行。連續3次釋放二進制信號量,只有第1次成功
  • B:發送任務進入阻塞態
  • C:接收任務得以執行,得到信號量,打印OK;再次去獲得信號量時,進入阻塞狀態
  • 在發送任務的vTaskDelay退出之前,運行的是空閑任務:現在發送任務、接收任務都阻塞了
  • D:發送任務再次運行,連續3次釋放二進制信號量,只有第1次成功
  • E:發送任務進入阻塞態
  • F:接收任務被喚醒,得到信號量,打印OK;再次去獲得信號量時,進入阻塞狀態
在這里插入圖片描述

運行結果如下圖所示,即使發送任務連續釋放多個信號量,也只能成功1次。釋放、獲得信號量是一一對應的。

在這里插入圖片描述

6.4 示例13: 防止數據丟失

本節代碼為: FreeRTOS_13_semaphore_circle_buffer

在示例12中,發送任務發出3次"提醒",但是接收任務只接收到1次"提醒",其中2次"提醒"丟失了。

這種情況很常見,比如每接收到一個串口字符,串口中斷程序就給任務發一次"提醒",假設收到多個字符、發出了多次"提醒"。當任務來處理時,它只能得到1次"提醒"。

你需要使用其他方法來防止數據丟失,比如:

在串口中斷中,把數據放入緩沖區

在任務中,一次性把緩沖區中的數據都讀出

簡單地說,就是:你提醒了我多次,我太忙只響應你一次,但是我一次性拿走所有數據

main函數中創建了一個二進制信號量,然后創建2個任務:一個用于釋放信號量,另一個用于獲取信號量,代碼如下:

/* 二進制信號量句柄 */
SemaphoreHandle_t xBinarySemaphore;

int main( void )
{
	prvSetupHardware();
	
    /* 創建二進制信號量 */
    xBinarySemaphore = xSemaphoreCreateBinary( );

	if( xBinarySemaphore != NULL )
	{
		/* 創建1個任務用于釋放信號量
		 * 優先級為2
		 */
		xTaskCreate( vSenderTask, "Sender", 1000, NULL, 2, NULL );

		/* 創建1個任務用于獲取信號量
		 * 優先級為1
		 */
		xTaskCreate( vReceiverTask, "Receiver", 1000, NULL, 1, NULL );

		/* 啟動調度器 */
		vTaskStartScheduler();
	}
	else
	{
		/* 無法創建二進制信號量 */
	}

	/* 如果程序運行到了這里就表示出錯了, 一般是內存不足 */
	return 0;
}

發送任務、接收任務的代碼和執行流程如下:

  • A:發送任務優先級高,先執行。連續寫入3個數據、釋放3個信號量:只有1個信號量起作用
  • B:發送任務進入阻塞態
  • C:接收任務得以執行,得到信號量
  • D:接收任務一次性把所有數據取出
  • E:接收任務再次嘗試獲取信號量,進入阻塞狀態
  • 在發送任務的vTaskDelay退出之前,運行的是空閑任務:現在發送任務、接收任務都阻塞了
  • F:發送任務再次運行,連續寫入3個數據、釋放3個信號量:只有1個信號量起作用
  • G:發送任務進入阻塞態
  • H:接收任務被喚醒,得到信號量,一次性把所有數據取出
在這里插入圖片描述

程序運行結果如下,數據未丟失:

在這里插入圖片描述

6.5 示例14: 使用計數型信號量

本節代碼為: FreeRTOS_14_semaphore_counting

使用計數型信號量時,可以多次釋放信號量;當信號量的技術值達到最大時,再次釋放信號量就會出錯。

如果信號量計數值為n,就可以連續n次獲取信號量,第(n+1)次獲取信號量就會阻塞或失敗。

main函數中創建了一個計數型信號量,最大計數值為3,初始值計數值為0;然后創建2個任務:一個用于釋放信號量,另一個用于獲取信號量,代碼如下:

/* 計數型信號量句柄 */
SemaphoreHandle_t xCountingSemaphore;

int main( void )
{
	prvSetupHardware();
	
    /* 創建計數型信號量 */
    xCountingSemaphore = xSemaphoreCreateCounting(3, 0);

	if( xCountingSemaphore != NULL )
	{
		/* 創建1個任務用于釋放信號量
		 * 優先級為2
		 */
		xTaskCreate( vSenderTask, "Sender", 1000, NULL, 2, NULL );

		/* 創建1個任務用于獲取信號量
		 * 優先級為1
		 */
		xTaskCreate( vReceiverTask, "Receiver", 1000, NULL, 1, NULL );

		/* 啟動調度器 */
		vTaskStartScheduler();
	}
	else
	{
		/* 無法創建信號量 */
	}

	/* 如果程序運行到了這里就表示出錯了, 一般是內存不足 */
	return 0;
}

發送任務、接收任務的代碼和執行流程如下:

  • A:發送任務優先級高,先執行。連續釋放4個信號量:只有前面3次成功,第4次失敗
  • B:發送任務進入阻塞態
  • CDE:接收任務得以執行,得到3個信號量
  • F:接收任務試圖獲得第4個信號量時進入阻塞狀態
  • 在發送任務的vTaskDelay退出之前,運行的是空閑任務:現在發送任務、接收任務都阻塞了
  • G:發送任務再次運行,連續釋放4個信號量:只有前面3次成功,第4次失敗
  • H:發送任務進入阻塞態
  • IJK:接收任務得以執行,得到3個信號量
  • L:接收任務再次獲取信號量時進入阻塞狀態
在這里插入圖片描述

運行結果如下圖所示:

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

    關注

    5082

    文章

    19104

    瀏覽量

    304828
  • Linux
    +關注

    關注

    87

    文章

    11292

    瀏覽量

    209334
  • RTOS
    +關注

    關注

    22

    文章

    811

    瀏覽量

    119595
  • FreeRTOS
    +關注

    關注

    12

    文章

    484

    瀏覽量

    62144
  • 信號量
    +關注

    關注

    0

    文章

    53

    瀏覽量

    8333
收藏 人收藏

    評論

    相關推薦

    實時操作系統FreeRTOS信號量應用

    二值信號量通常用于互斥訪問或同步,二值信號量和互斥信號量非常相似,但還是有細微差別,互斥信號量擁有優先級繼承機制,二值信號沒有。因此二值信
    的頭像 發表于 06-08 09:24 ?3700次閱讀
    實時操作系統<b class='flag-5'>FreeRTOS</b><b class='flag-5'>信號量</b>應用

    FreeRTOS串口中斷接收不定長的數據與二值信號量的使用

    FreeRTOS例程,使用串口中斷接收不定長的數據,以及二值信號量的使用
    的頭像 發表于 09-26 09:02 ?4174次閱讀
    <b class='flag-5'>FreeRTOS</b>串口中斷接收不定長的數據與二值<b class='flag-5'>信號量</b>的使用

    FreeRTOS信號量使用教程

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

    FreeRTOS信號量的使用與實例

    在嵌入式系統中,任務管理是一個重要的部分,它涉及到任務之間的通信和同步,信號量,隊列,互斥鎖和事件標志組等概念。本文將以 FreeRTOS 為例,詳細講解這些內容。
    的頭像 發表于 12-12 15:25 ?2543次閱讀

    轉:freeRTOS信號量學習

    信號量同樣是RTOS學習中很重要的一節,信號量可以用在共享資源或者同步任務中,對執行權的控制,誰擁有信號量誰擁有執行權,在freeRTOS信號量
    發表于 08-12 18:29

    FreeRTOS信號量介紹

    FreeRTOS信號量 & ESP32實戰閱讀建議:有一定操作系統基礎知識。FreeRTOS信號量1. 二值信號量??二值
    發表于 01-27 07:28

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

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

    FreeRTOS信號量 & ESP32實戰

    FreeRTOS信號量 & ESP32實戰閱讀建議:有一定操作系統基礎知識。FreeRTOS信號量1. 二值信號量??二值
    發表于 12-03 18:06 ?1次下載
    <b class='flag-5'>FreeRTOS</b><b class='flag-5'>信號量</b> & ESP32實戰

    FreeRTOS 隊列 信號量 互斥

    文章目錄前言Queue 隊列semaphore 信號量Mutex 互斥微信公眾號前言FreeRTOS STM32CubeMX配置 內存管理 任務管理上節介紹了用STM32CubeMX生成帶
    發表于 12-09 09:51 ?0次下載
    <b class='flag-5'>FreeRTOS</b> 隊列 <b class='flag-5'>信號量</b> 互斥<b class='flag-5'>量</b>

    FreeRTOS高級篇6---FreeRTOS信號量分析

    FreeRTOS信號量包括二進制信號量、計數信號量、互斥信號量(以后簡稱互斥)和遞歸互斥
    發表于 01-26 17:39 ?7次下載
    <b class='flag-5'>FreeRTOS</b>高級篇<b class='flag-5'>6---FreeRTOS</b><b class='flag-5'>信號量</b>分析

    FreeRTOS系列第20篇---FreeRTOS信號量API函數

    FreeRTOS信號量包括二進制信號量、計數信號量、互斥信號量(以后簡稱互斥)和遞歸互斥
    發表于 01-26 17:44 ?4次下載
    <b class='flag-5'>FreeRTOS</b><b class='flag-5'>系列</b>第20篇---<b class='flag-5'>FreeRTOS</b><b class='flag-5'>信號量</b>API函數

    在Arduino IDE中使用FreeRTOS信號量

    電子發燒友網站提供《在Arduino IDE中使用FreeRTOS信號量.zip》資料免費下載
    發表于 01-04 10:18 ?0次下載
    在Arduino IDE中使用<b class='flag-5'>FreeRTOS</b><b class='flag-5'>信號量</b>

    freeRTOS中最常用到的信號量有哪些

    在操作系統系統中,信號量通常用于控制對共享資源的訪問和任務之間進行同步,信號量在操作系統中是很常用的,也是學習freeRTOS操作系統必須要掌握的。
    的頭像 發表于 02-10 11:04 ?2137次閱讀
    <b class='flag-5'>freeRTOS</b>中最常用到的<b class='flag-5'>信號量</b>有哪些

    FreeRTOS的二值信號量

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

    FreeRTOS四種信號量詳細介紹

    1、二值信號量 二值信號量通常用于互斥訪問或同步,二值信號量和互斥信號量非常類似,但是還是有一些細微的差別,互斥信號量擁有優先級繼承機制,二
    的頭像 發表于 07-06 17:14 ?2590次閱讀
    主站蜘蛛池模板: 草比比过程图| 伊人大香人妻在线播放| 久久囯产精品777蜜桃传媒| 爱做久久久久久| 一本久道久久综合婷婷五月 | 18 japanese宾馆直播| 偷拍精品视频一区二区三区| 麻豆XXXX乱女少妇精品| 国产在线观看码高清视频| 成年妇女免费播放| 最新果冻传媒在线观看免费版| 性做久久久久免费观看| 青青青草免费| 奶头被客人吸得又红又肿| 精品国产午夜肉伦伦影院| 国产精品亚洲视频在线观看| a级男女性高爱潮高清试看| 又亲又揉摸下面视频免费看 | 九九热这里都是精品| 国产精品伦一区二区三级视频| www.精品久久| 97精品国产高清在线看入口| 一个人视频日本在线观看| 香蕉动漫库| 污漫日本E同人| 熟妇的味道HD中文字幕| 人人舔人人爱| 日本久久道一区二区三区| 欧美性色xo影院69| 欧美日韩中文字幕综合图区| 免费观看亚洲视频| 美女也烦恼主题曲| 蜜桃麻豆WWW久久囤产精品免费 | 97久久久久| 99精品中文字幕在线观看| 97超碰在线视频 免费| 97成人精品视频在线播放| 3d无遮挡h肉动漫在线播放 | 日本精品久久久久中文字幕2 | 穿白丝袜边走边尿白丝袜| 芳草地在线观看免费观看|