FreeRTOS-信号量

1. 二进制信号量创建(Binary Semaphore)

函数原型

//该函数不接受任何参数,并返回一个指向新创建的二进制信号量的句柄(即 SemaphoreHandle_t 类型)。
SemaphoreHandle_t xSemaphoreCreateBinary( void );

应用程序可以使用此句柄对该信号量进行操作,例如获取(take)和释放(give)。

函数解析

二进制信号量是一种特殊类型的信号量,它只有两种状态:0 和 1。典型的用法是实现任务之间的互斥访问共享资源。

当一个任务需要访问资源时,它可以尝试获取二进制信号量。

如果信号量的值为 0,则任务将被阻塞。只有当其他任务释放了该信号量,使其值变为 1 时,任务才能继续执行。

需要注意的是,二进制信号量在使用过程中应遵循正确的获取和释放顺序,以避免死锁和资源竞争问题。

另外,二进制信号量不能直接通过中断服务程序(ISR)来获取和释放,而是需要使用 xSemaphoreTakeFromISR 和 xSemaphoreGiveFromISR 这两个函数。

示例

//1.包含 FreeRTOS 头文件:
#include "FreeRTOS.h"
#include "semphr.h"

//2.在适当的位置调用 xSemaphoreCreateBinary 函数来创建二进制信号量,并获取返回的信号量句柄:
SemaphoreHandle_t binarySemaphore = xSemaphoreCreateBinary();

//3.在需要的地方使用信号量进行任务同步。例如,在任务 A 中需要访问一个共享资源时,
//可以使用 xSemaphoreTake 函数获取信号量并在完成后使用 xSemaphoreGive 函数释放信号量
// Task A
xSemaphoreTake(binarySemaphore, portMAX_DELAY);
// 访问共享资源的代码
xSemaphoreGive(binarySemaphore);

//4. 在另一个任务(例如任务 B)中,如果需要等待任务 A 完成后才能执行一些操作,可以尝试
//获取二进制	信号量。如果信号量被任务 A 获取并且未释放,则任务 B 将被阻塞直到信号量可用:
// Task B
xSemaphoreTake(binarySemaphore, portMAX_DELAY);
// 在任务 A 完成后执行的代码
xSemaphoreGive(binarySemaphore);

2. 计数信号量(Counting Semaphore)

函数原型

计数信号量是一种用来控制多个任务对共享资源的访问的同步机制,它可以允许多个任务同时访问同一个资源,但是通过计数来限制同时访问该资源的任务数量。

SemaphoreHandle_t xSemaphoreCreateCounting( UBaseType_t uxMaxCount, UBaseType_t uxInitialCount );
//uxMaxCount:信号量的最大计数值,即该信号量允许的最大计数。
//uxInitialCount:信号量的初始计数值,即在创建时设定的初始计数。

示例

SemaphoreHandle_t xCountingSemaphore;
xCountingSemaphore = xSemaphoreCreateCounting(10, 0);

创建完成后,可以在任务中使用这个信号量来控制对共享资源的访问,
比如在任务中需要访问某个共享资源时,首先尝试获取信号量,
如果获取成功则可以访问资源,访问结束后再释放信号量,以便其他任务也可以访问该资源。

3. 获取(占用)一个信号量

函数原型

BaseType_t xSemaphoreTake(SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait);
//xSemaphore:要获取的信号量的句柄。
//xTicksToWait:等待获取信号量的最长时间,可以设置为portMAX_DELAY表示永久等待,也可以设置为其他数值表示等待的最大时间。

它的作用是尝试获取一个信号量,如果信号量当前不可用(即其计数为0),则任务将会等待,直到信号量变为可用为止。

一旦成功获取了信号量,函数将会返回pdTRUE;如果在指定的时间内未能获取到信号量,函数将会返回pdFALSE。

函数解析

xSemaphoreTake函数的使用通常结合信号量的创建和初始化,以及与xSemaphoreGive函数配合使用,来实现多任务之间的同步和资源访问的互斥操作。

通过合理地使用xSemaphoreTake函数,可以有效地控制任务对共享资源的访问,避免竞争条件和数据损坏的发生,确保系统的正确性和稳定性。

4. 释放一个信号量

函数原型

BaseType_t xSemaphoreGive(SemaphoreHandle_t xSemaphore);
//xSemaphore 是待释放的信号量的句柄,函数返回一个 BaseType_t 类型的值,用于指示是否成功释放信号量。

它的作用是将一个信号量的计数值加一,表示释放了一个资源或者完成了一个操作,使得其他任务可以获取该信号量并继续执行。该函数的原型通常如下:

函数解析

在使用xSemaphoreGive函数时,
如果有任务在等待该信号量,它会使得其中一个等待的任务可以继续执行;
如果没有任务在等待,那么信号量的计数值会加一,表示有一个资源可用。

需要注意的是,在实际应用中,我们通常会在获取信号量后对资源进行操作,
然后使用xSemaphoreGive函数来释放信号量,以确保资源能够被正确地共享和释放。

注意事项

信号量的使用有两种方式先释放信号量再获取信号量先获取信号量再释放信号量有一些区别

  1. 先释放信号量再获取信号量
  • 任务 A 先调用 xSemaphoreGive 函数释放信号量,增加信号量的计数值。
  • 任务 B 在需要访问共享资源之前,调用 xSemaphoreTake 函数尝试获取信号量。因为信号量的计数值已经增加,任务 B 可以成功获取信号量,并继续执行。
  • 这种顺序适用于某个任务在完成操作后,主动释放信号量给其他等待该资源的任务使用。
  1. 先获取信号量再释放信号量
  • 任务 A 先调用 xSemaphoreTake 函数尝试获取信号量。如果信号量可用(计数值大于 0),任务 A 可以成功获取信号量,并继续执行;如果信号量不可用(计数值为 0),任务 A 会被阻塞等待直到有其他任务释放信号量。
  • 任务 B 在需要访问共享资源之前,调用 xSemaphoreGive 函数释放信号量,增加信号量的计数值。
  • 这种顺序适用于某个任务等待其他任务完成操作并释放信号量后,再获取信号量并继续执行。

总结:

  • 先释放信号量再获取信号量适用于任务主动释放资源给其他等待任务使用的情况
  • 先获取信号量再释放信号量适用于任务等待其他任务完成操作并释放资源后,再获取资源并继续执行的情况

5. 递归调用信号量

xSemaphoreTakeRecursive 
xSemaphoreGiveRecursive

这两个函数用于在递归调用中获取和释放信号量,以防止死锁。

6. 中断服务程序(ISR)获取和释放信号量

函数原型

在实时操作系统中,由于中断的特殊性,通常不能直接调用阻塞型的函数,因此需要使用专门设计用于中断环境的函数来进行同步操作。

BaseType_t xSemaphoreTakeFromISR( SemaphoreHandle_t xSemaphore, BaseType_t *pxHigherPriorityTaskWoken );
//SemaphoreHandle_t xSemaphore:需要获取的信号量句柄
//BaseType_t *pxHigherPriorityTaskWoken:用于指示在调用此函数后是否有高优先级任务需要立即唤醒。

BaseType_t xSemaphoreGiveFromISR( SemaphoreHandle_t xSemaphore, BaseType_t *pxHigherPriorityTaskWoken );
//SemaphoreHandle_t xSemaphore:需要释放的信号量句柄
//BaseType_t *pxHigherPriorityTaskWoken:用于指示在调用此函数后是否有高优先级任务需要立即唤醒。

这两个函数用于在中断服务程序(ISR)中获取和释放信号量,因为在 ISR 中无法直接使用标准的获取和释放函数。

函数解析

pxHigherPriorityTaskWoken参数的使用
当在ISR中调用与任务同步相关的函数时,可能会导致等待中的任务的优先级得到提升,这时就需要使用pxHigherPriorityTaskWoken参数来进行任务切换。

这个参数是一个指向BaseType_t类型的指针,BaseType_t类型实际上就是一个整数类型,通常是typedef为int。

当在ISR中设置*pxHigherPriorityTaskWoken为pdTRUE(通常对应值为1)时,意味着有一个或多个任务的优先级被提升了,内核在退出ISR后会检查这个标记,

如果发现有任务的优先级提升了,就会立即进行任务切换,确保高优先级任务能够及时得到执行。

举例来说,当在ISR中释放一个信号量时,如果此操作导致了等待任务的优先级得以提升,那么就需要将pxHigherPriorityTaskWoken设置为pdTRUE,以便在ISR退出后立即进行任务切换。

总之,pxHigherPriorityTaskWoken参数的作用在于在ISR中标记是否有需要唤醒的更高优先级任务,以便在适当的时机进行任务切换。这样能够提高系统的响应速度和实时性,确保高优先级任务能够及时得到执行。

示例

在这个示例中,当在ISR中调用xSemaphoreGiveFromISR函数给出信号量时,
如果有需要唤醒更高优先级的任务存在,xHigherPriorityTaskWoken将被设置为pdTRUE。
然后可以使用portYIELD_FROM_ISR函数进行任务切换,以便唤醒更高优先级的任务。

void yourInterruptHandler() 
{
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    // 给予信号量,可能唤醒一个阻塞的任务
    xSemaphoreGiveFromISR(xSemaphore, &xHigherPriorityTaskWoken);
    // 判断是否有需要唤醒更高优先级的任务存在
    if (xHigherPriorityTaskWoken == pdTRUE) 
    {
        // 有需要唤醒更高优先级的任务存在,进行任务切换
        portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值