6.4 Binary Semaphores Used for Synchronization
[[FreeRTOS_Mastering_the_FreeRTOS_Real_Time_Kernel-A_Hands-On_Tutorial_Guide.pdf#page=218&selection=5,0,7,42|FreeRTOS_Mastering_the_FreeRTOS_Real_Time_Kernel-A_Hands-On_Tutorial_Guide, page 218]]
209 4.1 vSemaphoreCreateBinary()
[[FreeRTOS_Reference_Manual_V10.0.0.pdf#page=209&selection=0,3,4,24|FreeRTOS_Reference_Manual_V10.0.0, page 209]]
上面是旧的信号量创建函数,已不再推荐使用,在新版本中,应使用如下函数:
4.2 xSemaphoreCreateBinary()
[[FreeRTOS_Reference_Manual_V10.0.0.pdf#page=212&selection=2,0,4,24|FreeRTOS_Reference_Manual_V10.0.0, page 212]]
如同红绿灯一样,控制任务(Task)进行同步,哪些任务可以优先执行,哪些任务可以暂停。
二进制信号量只有两个值,要么0要么1,1 的时候就开始执行,0 的时候停止执行,经常使用信号量的方式进行同步。
xSemaphoreCreateBinary():#include "FreeRTOS.h"
#include "semphr.h"
SemaphoreHandle_t xSemaphoreCreateBinary( void );
函数说明:
参数:
None:无参数。返回值:
NULL: FreeRTOS 的堆中没有足够的内存,无法创建信号量句柄。Any other value:信号量创建成功,返回一个可以引用的信号量句柄。注意:
也就是说,我持有,但是你的地位高,并且你要,因而我的地位会和你一样高,让你获取不到互斥锁。
SemaphoreHandle_t,并且可以在任何用此类型形参的 API 函数中使用。xSemaphoreCreateBinary()创建的信号量。xSemaphoreTake()#include "FreeRTOS.h"
#include "semphr.h"
BaseType_t xSemaphoreTake( SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait );
函数说明:
xSemaphoreCreate(), xSemaphoreCreateCounting(), xSemaphoreCreateMutex()创建的信号量。参数:
xSemaphore:用于获取信号量的句柄。xTicksToWait:超时等待时间。返回值:
pdPASS:成功获取到信号量。pdFAIL:获取信号量失败。注意事项:
xSemaphoreGive()#include "FreeRTOS.h"
#include "semphr.h"
BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore );
函数说明:
vSemaphoreCreateBinary(), xSemaphoreCreateCounting(), xSemaphoreCreateMutex(),用这些函数创建信号量之后,均应使用此函数来先释放信号量。参数:
xSemaphore:需要被释放的信号量句柄。返回值:
pdPASS:释放信号量成功。pdFAIL:信号量释放失败,因为调用此函数的任务并非信号量的持有者。任何任务必须成功“获取”信号量,然后才能“归还”信号量。需要在创建信号量之后(
xSemaphoreCreateBinary()...),用此函数(xSemaphoreGive())首先给一个信号量,才能正常锁住数据。
此处代码信号量的作用是“锁住”数据,即 一个任务对数据进行修改时,另一个任务不可对相同的数据修改。
#include <stdio.h>
#include <inttypes.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_flash.h"
#include "esp_system.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
static SemaphoreHandle_t semaphore_handle; // 创建信号量句柄,公共使用
static int count = 0; // 即将上锁的数据
void task_1(void *pvPara)
{
while (true) {
// 开启(拿走)信号,即表明,“我”要对数据进行更改了,另一个任务不可同时对公共数据修改
xSemaphoreTake(semaphore_handle, portMAX_DELAY);
for (int i = 0; i < 10; i++) {
count++;
printf("[TASK 1]count = %d\n", count);
vTaskDelay(pdMS_TO_TICKS(1000));
}
// 把信号还回去,即 其他任务可以对公共数据修改了
xSemaphoreGive(semaphore_handle);
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
void task_2(void *pvPara)
{
while (true) {
xSemaphoreTake(semaphore_handle, portMAX_DELAY);
for (int i = 0; i < 10; i++) {
count++;
printf("[TASK 2]count = %d\n", count);
vTaskDelay(pdMS_TO_TICKS(1000));
}
xSemaphoreGive(semaphore_handle);
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
void app_main(void)
{
// 创建信号量
semaphore_handle = xSemaphoreCreateBinary();
// 信号量创建完成后,首先要给予一个信号
xSemaphoreGive(semaphore_handle);
xTaskCreate(task_1, "Task 1", 2048, (void *)semaphore_handle, 1, NULL);
xTaskCreate(task_2, "Task 2", 2048, (void *)semaphore_handle, 1, NULL);
}

程序输出表明,两个任务分别对公共数据进行连续读写,在一个任务读写数据时,另一个任务完全不干扰。如果不用信号量对数据上锁,则两个任务会交替续写公共数据。
相当于信号灯,Task 1 绿灯时,有权读写数据,而 Task 2 无权读写;Task 2 绿灯时,有权读写数据, 而 Task 1 无权读写数据。