提示: 在许多使用场景中,使用直达任务通知要比使用二进制信号量的速度更快,内存效率更高。
semphr. h
SemaphoreHandle_t xSemaphoreCreateBinary( void );
创建一个二进制信号量,并返回一个可以引用该信号量的 句柄。 configSUPPORT_DYNAMIC_ALLOCATION 必须在 FreeRTOSConfig.h 中被设置为 1,或保留未定义状态(此时,它默认 (此时默认为1),才能使用RTOSAPI函数。
每个二进制信号量需要少量RAM,用于保持 信号量的状态。 如果使用 xSemaphoreCreateBinary() 创建二进制信号量 则会从RAM堆FreeRTOS中自动分配所需的 。 如果使用 xSemaphoreCreateBinaryStatic() 创建二进制信号量, 那么RAM由应用程序编写者提供,这需要用到一个附加参数, 但允许在编译时静态分配 RAM 。
信号量是在“空”状态下创建的,这意味着必须先用 xSemaphoreGive() API 函数给出信号量, 然后才能使用 xSemaphoreTake() 函数来获取(获得)该信号量。
二进制信号量和相互锁非常相似,但 仍有一些细微差异: 互斥锁具有优先级继承机制, 但二进制信号量没有。 因此,二进制信号量是 实现同步的更好选择(任务之间或任务与中断之间), 而互斥锁是实现简单互斥的更好选择。
二值信号量并不需要在得到后立即释放, 因此,任务同步可以通过一个任务/中断持续释放信号量 而另外一个持续获得信号量来实现。 相关演示请参阅 xSemaphoreGiveFromISR()文档页面上的代码示例。 请注意, 使用直达任务通知往往可以更有效地实现相同的功能。
如果另一个优先级更高的任务试图获得相同的互斥锁, 那么“获取”互斥锁的任务的优先级就有可能被提高。 拥有互斥锁的任务“继承”了 试图“获取”相同互斥锁任务的优先级, 这意味着必须始终“返回”互斥锁,否则 优先级较高的任务将永远无法获得互斥锁, 而优先级较低的任务将永远无法“取消继承”优先级。
互斥锁和二进制信号量都由 SemaphoreHandle_t 类型的变量引用,同时可以 在任何采用该类型参数的任务级 API 函数中使用。 与互斥锁不同, 二进制信号量可用于中断服务程序。
NULL 创建信号量失败, 因为 FreeRTOS堆栈 不足。其它值 信号量已成功创建。 返回 值是一个句柄,通过该句柄可以引用信号量。
SemaphoreHandle_t xSemaphore;
void vATask( void * pvParameters )
{
/* Attempt to create a semaphore. */
xSemaphore = xSemaphoreCreateBinary();
if( xSemaphore == NULL )
{
/* There was insufficient FreeRTOS heap available for the semaphore to
be created successfully. */
}
else
{
/* The semaphore can now be used. Its handle is stored in the
xSemahore variable. Calling xSemaphoreTake() on the semaphore here
will fail until the semaphore has first been given. */
}
}
semphr. h
SemaphoreHandle_t xSemaphoreCreateBinaryStatic(
StaticSemaphore_t *pxSemaphoreBuffer );
创建一个二进制信号量,并返回一个可以引用该信号量的 。 configSUPPORT_STATIC_ALLOCATION 必须在 FreeRTOSConfig.h 中设置为 1,该 RTOS API 函数才可用。
每个二进制信号量需要少量 RAM 来保存信号量状态。 如果二进制信号量是使用 xSemaphoreCreateBinary() 创建的, 则会从 FreeRTOS 堆中自动分配所需的 RAM。 如果二进制信号量是使用 xSemaphoreCreateBinaryStatic() 创建的, 则 RAM 由应用程序编写器提供,这需要用到一个附加参数, 但允许在编译时静态分配 RAM 。 请参阅静态分配与 动态分配页面了解更多信息。
信号量是在“空”状态下创建的,这意味着必须先用 xSemaphoreGive() API 函数给出信号量, 然后才能使用 xSemaphoreTake() 函数来获取(获得)该信号量。
二进制信号量和相互锁非常相似,但 仍有一些细微差异: 互斥锁具有优先级继承机制, 但二进制信号量没有。 因此,二进制信号量是 实现同步的更好选择(任务之间或任务与中断之间), 而互斥锁是实现简单互斥的更好选择。
二值信号量并不需要在得到后立即释放, 因此,任务同步可以通过一个任务/中断持续释放信号量 而另外一个持续获得信号量来实现。 相关演示请参阅 xSemaphoreGiveFromISR()文档页面上的代码示例。 请注意, 使用直达任务通知往往可以更有效地实现相同的功能。
如果另一个优先级更高的任务试图获得相同的互斥锁, 那么“获取”互斥锁的任务的优先级就有可能被提高。 拥有互斥锁的任务“继承”了 试图“获取”相同互斥锁任务的优先级, 这意味着必须始终“返回”互斥锁,否则 优先级较高的任务将永远无法获得互斥锁, 而优先级较低的任务将永远无法“取消继承”优先级。 用于实现互斥的互斥锁实例, 请参阅 xSemaphoreTake() 文档页面。
互斥锁和二进制信号量都由 SemaphoreHandle_t 类型的变量引用,同时可以 在任何采用该类型参数的任务级 API 函数中使用。 与互斥锁不同, 二进制信号量可用于中断服务程序。
pxSemaphoreBuffer 必须指向 StaticSemaphore_t 类型的变量, 该变量将用于保存信号量的状态。
NULL 因为 pxSemaphoreBuffer 为 NULL, 所以无法创建信号量。其他任何值 信号量已成功创建。 返回 值是一个句柄,通过该句柄可以引用信号量。
SemaphoreHandle_t xSemaphore = NULL;
StaticSemaphore_t xSemaphoreBuffer;
void vATask( void * pvParameters )
{
/* Create a binary semaphore without using any dynamic memory
allocation. The semaphore's data structures will be saved into
the xSemaphoreBuffer variable. */
xSemaphore = xSemaphoreCreateBinaryStatic( &xSemaphoreBuffer );
/* The pxSemaphoreBuffer was not NULL, so it is expected that the
handle will not be NULL. */
configASSERT( xSemaphore );
/* Rest of the task code goes here. */
}
semphr. h
vSemaphoreCreateBinary(SemaphoreHandle_t xSemaphore)
**注意:**vSemaphoreCreateBinary() 宏保留在源代码中, 以确保后向兼容,但不应在新设计中使用。 新设计中应使用 xSemaphoreCreateBinary() 函数。
此外,在许多情况下,使用 直达任务通知 代替二进制信号量速度更快,更节省内存。
使用现有队列机制创建信号量的宏。队列长度为 1 ,因为这是二进制信号量。数据大小为 0 ,因为实际上我们并不会存储任何数据,只想知道队列为空还是满。
二进制信号量和互斥锁非常相似,但有一些小差异: 互斥锁包含优先继承机制, 而二进制信号量不包含。 因此,二进制信号量更适合(在任务间或任务与中断之间)实现同步, 而互斥锁更适合实现简单 互斥。
一旦获得二进制信号量,则无需返回, 因此任务同步可以通过一个任务/中断连续“提供”信号量, 而另一个任务/中断连续“获取”信号量来实现。 可以通过 xSemaphoreGiveFromISR() 文档页面上的示例代码来演示。
如果另一个优先级更高的任务尝试获取相同的互斥锁, 那么“获取”互斥锁的任务的优先级就有可能被提高。 拥有互斥锁的任务“继承”了 试图“获取”相同互斥锁任务的优先级, 这意味着必须始终“返回”互斥锁,否则 优先级较高的任务将永远无法获得互斥锁, 而优先级较低的任务将永远无法“取消继承”优先级。 用于实现互斥的互斥锁实例, 详见 xSemaphoreTake() 文档页面。
互斥锁和二进制信号量都分配给了 SemaphoreHandle_t 类型的变量, 可在任何采用此类型参数的 API 函数中使用。
xSemaphore 已创建信号量的句柄,应为 SemaphoreHandle_t 类型。
` SemaphoreHandle_t xSemaphore;`
void vATask( void * pvParameters )
{
// Semaphore cannot be used before a call to vSemaphoreCreateBinary ().
// This is a macro so pass the variable in directly.
vSemaphoreCreateBinary( xSemaphore );
if( xSemaphore != NULL )
{
// The semaphore was created successfully.
// The semaphore can now be used.
}
}
semphr. h
SemaphoreHandle_t xSemaphoreCreateCounting( UBaseType_t uxMaxCount,
`UBaseType_t uxInitialCount);
创建计数信号量 并返回句柄,通过该句柄可以引用新创建的信号量。 configSUPPORT_DYNAMIC_ALLOCATION 必须在 FreeRTOSConfig.h 中被设置为 1,或保留未定义状态(此时,它默认 默认为1) ,才能使用此RTOS API 函数。
每个计数信号量需要少量RAM ,用于保持 信号量的状态。 如果使用 xSemaphoreCreateCounting () 创建计数信号量 则会从 堆自动分配所需的。 RAM FreeRTOS 如果使用 xSemaphoreCreateCountingStatic() 创建计数信号量, 则 RAM会由应用程序编写器提供,这需要其他的 但允许在编译时静态分配 RAM 。
盘点事件。
在此使用场景中, 每次发生事件(增加信号量计数值)时 ,事件处理程序都会“给出”信号量,处理程序任务 每次处理事件时,都会“获取”信号量 (递减信号量计数值)。 因此,计数值是 已发生的事件数量和 已处理的数量之间的差。 在这种情况下, 初始计数值最好为零。
请注意, 使用直接到任务通知通常可以更有效地实现相同的功能。
资源管理。
在此使用方案中,计数值表示可用的资源数量 。 若要获取对资源的控制权,任务就必须首先获取 信号量-递减信号量计数值。 当计数值 达到零,则表示没有可用资源。 当任务结束使用 资源时,它会“返回”信号量-增加信号量计数 值。 在这种情况下,初始计数值最好 等于所述最大计数值,表明所有资源都是可用的。
uxMaxCount 可以达到的最大计数值。 当信号量达到此值时,它不能再被“给定”。
uxInitialCount 创建信号量时分配给信号量的计数值。
如果已成功创建信号量,则将返回该信号量的句柄 。 如果因为保留信号量所需的RAM 无法分配而无法创建信号量, 则会返回 NULL。
void vATask( void * pvParameters )
{
SemaphoreHandle_t xSemaphore;
/* Create a counting semaphore that has a maximum count of 10 and an
initial count of 0. */
xSemaphore = xSemaphoreCreateCounting( 10, 0 );
if( xSemaphore != NULL )
{
/* The semaphore was created successfully. */
}
}
semphr. h
SemaphoreHandle_t xSemaphoreCreateCountingStatic(
UBaseType_t uxMaxCount,
UBaseType_t uxInitialCount
StaticSemaphore_t *pxSemaphoreBuffer ); );
创建计数信号量 并返回句柄,通过该句柄可以引用新创建的信号量。 configSUPPORT_STATIC_ALLOCATION 必须在 FreeRTOSConfig.h 中设置为 1才能使用此 RTOS API 函数。
每个计数信号量需要少量RAM ,用于保持 信号量的状态。 如果使用 xSemaphoreCreateCounting() 创建计数信号量, 则会从 RAM 堆FreeRTOS中自动分配所需的 。 如果使用 xSemaphoreCreateCountingStatic () 创建计数信号量, 则 RAM 由应用程序编写器提供,这需要用到一个附加参数, 但允许在编译时静态分配 RAM 。 请参阅静态分配与 动态分配页面以了解更多信息。
计数信号量通常用于两种情况:
盘点事件。
在此使用场景中, 每次发生事件(增加信号量计数值)时 ,事件处理程序都会“给出”信号量,处理程序任务 每次处理事件时,都会“获取”信号量 (递减信号量计数值)。 因此,计数值是 已发生的事件数量和 已处理的数量之间的差。 在这种情况下, 初始计数值最好为零。
请注意, 使用直接到任务通知通常可以更有效地实现相同的功能。
资源管理。
在此使用方案中,计数值表示可用的资源数量 。 若要获取对资源的控制权,任务就必须首先获取 信号量-递减信号量计数值。 当计数值 达到零,则表示没有可用资源。 当任务结束使用 资源时,它会“返回”信号量-增加信号量计数 值。 在这种情况下,初始计数值最好 等于所述最大计数值,表明所有资源都是可用的。
uxMaxCount 可以达到的最大计数值。 当信号量达到此值时,它不能再被“给定”。
uxInitialCount 创建信号量时分配给信号量的计数值。
pxSemaphoreBuffer 必须指向 StaticSemaphore_t 类型的变量, 该变量然后用于保存信号量的数据结构体。
如果已成功创建信号量,则将返回该信号量的句柄 。 如果 pxSemaphoreBuffer 为 NULL,则返回 NULL。
static StaticSemaphore_t xSemaphoreBuffer;
void vATask( void * pvParameters )
{
SemaphoreHandle_t xSemaphore;
/* Create a counting semaphore that has a maximum count of 10 and an
initial count of 0. The semaphore's data structures are stored in the
xSemaphoreBuffer variable - no dynamic memory allocation is performed. */
xSemaphore = xSemaphoreCreateCountingStatic( 10, 0, &xSemaphoreBuffer );
/* pxSemaphoreBuffer was not NULL so it is expected that the semaphore
will be created. */
configASSERT( xSemaphore );
}
semphr. h
SemaphoreHandle_t xSemaphoreCreateMutex( void )
创建互斥锁 ,并返回 一个该互斥锁可以引用的句柄。 中断服务例程中, 不能使用互斥锁。
configSUPPORT_DYNAMIC_ALLOCATION 和 configUSE_MUTEXES 必须同时在 FreeRTOSConfig.h 中设置为 1, 方能确保 xSemaphoreCreateMutex() 可用。(可不定义 configSUPPORT_DYNAMIC_ALOGRATION, 在这种情况下,它将默认为 1。)
每个互斥锁需要少量 RAM , 以此来保持互斥锁的状态。 如果使用 xSemaphoreCreateMutex () 创建互斥锁 则会从 RAM 堆FreeRTOS中自动分配所需的 。 如果使用 xSemaphoreCreateMutexStatic() 创建互斥锁, 那么应由应用程序编写人员提供 RAM, 但允许在编译时静态分配 RAM 。
使用 xSemaphoreTake () 获取互斥锁,并给出互斥锁 使用 xSemaphoreGive() 。 xSemaphoreTakeRecursive() 和 xSemaphoreGiveRecursive() 仅可用于 使用 xSemaphoreCreateRecursiveMutex () 创建的互斥锁。
互斥锁和二进制信号量极为相似,但 仍有一些细微差异: 互斥锁具有优先级继承机制, 但二进制信号量没有。 因此,二进制信号量是 实现同步的更好选择(任务之间或任务与中断之间), 也是实施简单互斥方面的更好选择。
如果另一个更高优先级的任务尝试获取相同的互斥锁, 则将暂时提高“获取”互斥锁的任务的优先级。 拥有互斥锁的任务 “继承”试图“获取”相同 互斥锁的任务的优先级。 这意味着必须始终“归还”互斥锁,否则 优先级较高的任务将始终无法获得互斥锁,而优先级较低 的始终无法“取消继承”优先级。
一旦获得二进制信号量,则无需要返回 因此,任务同步可以通过一个任务/中断持续释放信号量 而另外一个持续获得信号量来实现。 相关演示请参阅 xSemaphoreGiveFromISR() 文档页面上的示例代码。 请注意,可以使用直接任务通知以更有效的方式 实现相同功能。
对互斥锁和二进制信号量的句柄都分配给 SemaphoreHandle_t 类型的变量,并且可以在任何接受该类型参数的任务级别(与中断 安全相反)API 函数中使用。
如果已成功创建互斥锁类型信号量,则返回创建的 互斥锁的句柄。 如果 由于 创建递归互斥锁, 则返回 NULL。
SemaphoreHandle_t xSemaphore;
void vATask( void * pvParameters )
{
/* Create a mutex type semaphore. */
xSemaphore = xSemaphoreCreateMutex();
if( xSemaphore != NULL )
{
/* The semaphore was created successfully and
can be used. */
}
}
semphr. h
SemaphoreHandle_t xSemaphoreCreateMutexStatic(
StaticSemaphore_t *pxMutexBuffer );
创建互斥锁 ,并返回 一个该互斥锁可以引用的句柄。 中断服务例程中, 不能使用互斥锁。
configSUPPORT_STATIC_ALLOCATION 和 configUSE_mutexes 必须同时在 FreeRTOSConfig.h 中设置为 1, xSemaphoreCreateMutexStatic () 才可用。
每个互斥锁需要少量 RAM , 以此来保持互斥锁的状态。 如果使用 xSemaphoreCreateMutex () 创建互斥锁 则会从 RAM 堆FreeRTOS中自动分配所需的 。 如果使用 xSemaphoreCreateMutexStatic () 创建互斥锁 则 RAM 由应用程序编写器提供,这需要用到一个附加参数, 但允许在编译时静态分配 RAM 。
使用 xSemaphoreTake () 获取互斥锁,并给出互斥锁 使用 xSemaphoreGive() 。 xSemaphoreTakeRecursive() 和 xSemaphoreGiveRecursive() 仅可用于 使用 xSemaphoreCreateResursiveMutex () 创建的互斥体。
互斥锁和二进制信号量极为相似,但 仍有一些细微差异: 互斥锁具有优先级继承机制, 但二进制信号量没有。 因此,二进制信号量是 实现同步的更好选择(任务之间或任务与中断之间), 也是实施简单互斥方面的更好选择。
如果另一个更高优先级的任务尝试获取相同的互斥锁, 则将暂时提高“获取”互斥锁的任务的优先级。 拥有互斥锁的任务 “继承”试图“获取”相同 互斥锁的任务的优先级。 这意味着必须始终“归还”互斥锁,否则 优先级较高的任务将始终无法获得互斥锁,而优先级较低 的始终无法“取消继承”优先级。
一旦获得二进制信号量,则无需要返回 因此,任务同步可以通过一个任务/中断持续释放信号量 而另外一个持续获得信号量来实现。 相关演示请参阅 xSemaphoreGiveFromISR() 文档页面上的示例代码。 请注意,可以使用直接任务通知以更有效的方式 实现相同功能。
对互斥锁和二进制信号量的句柄都分配给 SemaphoreHandle_t 类型的变量,并且可以在任何接受该类型参数的任务级别(与中断 安全相反)API 函数中使用。
pxMutexBuffer 必须指向 StaticSemaphore_t 类型的变量, 该变量将用于保存互斥锁型信号量的状态。
如果已成功创建互斥锁类型信号量,则返回创建的 互斥锁的句柄。 如果 因为 pxMutexBuffer 是 NULL 而未创建互斥锁,那么返回 NULL。
SemaphoreHandle_t xSemaphore = NULL;
StaticSemaphore_t xMutexBuffer;
void vATask( void * pvParameters )
{
/* Create a mutex semaphore without using any dynamic memory
allocation. The mutex's data structures will be saved into
the xMutexBuffer variable. */
xSemaphore = xSemaphoreCreateMutexStatic( &xMutexBuffer );
/* The pxMutexBuffer was not NULL, so it is expected that the
handle will not be NULL. */
configASSERT( xSemaphore );
/* Rest of the task code goes here. */
}
semphr. h
SemaphoreHandle_t xSemaphoreCreateRecursiveMutex( void )
创建一个递归互斥锁 , 并返回一个互斥锁 句柄。 不能在中断服务程序中使用递归互斥锁。 configSUPPORT_DYNAMIC_ALLOCATION 和 configUSE_RECURSIVE_mutexes 都必须在 FreeRTOSConfig.h 中定义为 1, 才能使用 xSemaphoreCreateRecursiveMutex() 函数(configSUPPORT_DYNAMIC_ALOUTION 也可以不定义,此时将默认定义为 1)。
每个递归互斥锁都需要少量RAM用于保持 递归互斥锁的状态。 如果使用 xSemaphoreCreateRecursiveMutex() 创建互斥锁, 则会从 RAM堆FreeRTOS栈中自动分配所需的。 如果一个递归互斥锁是使用 xSemaphoreCreateRecursiveMutexStatic() 创建的, 那么RAM由应用程序编写者提供,这需要用到一个附加参数, 但允许在编译时静态分配 RAM 。
分别使用 xSemaphoreTakeRecursive()来获取(持有), 和 xSemaphoreGiveRecursive() API函数释放。 不得使用 xSemaphoreTake() 和 xSemaphoreGive()。
xSemaphoreCreateMutex()和 xSemaphoreCreateMutexStatic()用于创建非递归互斥锁。 非递归互斥锁只能被一个任务 获取一次, 如果同一个任务想再次获取则会失败, 因为当任务第一次释放互斥锁时,互斥锁就一直 处于释放状态。
与非递归互斥锁相反,递归互斥锁可以被同一个任务获取很多次, 获取多少次就需要释放多少次, 此时才会返回递归互斥锁。
与非递归互斥锁一样,递归互斥锁采用优先级继承 算法。 如果另一个优先级更高的任务试图获得相同的互斥锁, 则将暂时提高“获取”互斥锁的任务的优先级。 拥有互斥锁的任务 “继承”试图“获取”相同 互斥锁的任务的优先级。 这意味着必须始终“归还”互斥锁,否则 优先级较高的任务将始终无法获得互斥锁,而优先级较低 的任务将永远无法“取消继承”优先级。
如果成功创建了递归互斥锁,那么将返回 创建的互斥锁的句柄。 如果因为保存互斥锁所需内存不能分配 从而没有 创建递归互斥锁, 则返回 NULL。
SemaphoreHandle_t xMutex;
void vATask( void * pvParameters )
{
Create a recursive mutex.
xMutex = xSemaphoreCreateRecursiveMutex();
if( xMutex != NULL )
{
/* The recursive mutex was created successfully and
can now be used. */
}
}
semphr. h
SemaphoreHandle_t xSemaphoreCreateRecursiveMutexStatic(
StaticSemaphore_t *pxMutexBuffer )
创建一个递归互斥锁 , 并返回一个互斥锁 句柄。 不能在中断服务程序中使用递归互斥锁。 configUSE_RECURSIVE_MUTEXES 和 configSUPPORT_STATIC_ALLOCATION 都必须在 FreeRTOSConfig.h 中设置为 1, xSemaphoreCreateRecursiveMutexStatic() 才可用。
每个递归互斥锁都需要少量 RAM 递归互斥锁的状态。 如果使用 xSemaphoreCreateRecursiveMutex() 创建互斥锁, 则会从 RAM堆FreeRTOS栈中自动分配所需的。 如果一个递归互斥锁是使用 xSemaphoreCreateRecursiveMutexStatic() 创建的, 那么RAM由应用程序编写者提供,这需要用到一个附加参数, 但允许在编译时静态分配 RAM 。
分别使用 xSemaphoreTakeRecursive()来获取(持有), 和 xSemaphoreGiveRecursive() API函数释放。 不得使用 xSemaphoreTake() 和 xSemaphoreGive()。
xSemaphoreCreateMutex()和 xSemaphoreCreateMutexStatic()用于创建非递归互斥锁。 非递归互斥锁只能被一个任务 获取一次, 如果同一个任务想再次获取则会失败, 因为当任务第一次释放互斥锁时,互斥锁就一直 处于释放状态。
与非递归互斥锁相反,递归互斥锁可以被同一个任务获取很多次, 获取多少次就需要释放多少次, 此时才会返回递归互斥锁。
与非递归互斥锁一样,递归互斥锁采用优先级继承 算法。 如果另一个优先级更高的任务试图获得相同的互斥锁, 则将暂时提高“获取”互斥锁的任务的优先级。 拥有互斥锁的任务 “继承”试图“获取”相同 互斥锁的任务的优先级。 这意味着必须始终“归还”互斥锁,否则 优先级较高的任务将始终无法获得互斥锁,而优先级较低 的始终无法“取消继承”优先级。
pxMutexBuffer 必须指向 StaticSemaphore_t 类型的变量, 该变量将用于保存互斥锁型信号量的状态。
如果已成功创建递归互斥锁,则返回创建的 创建的互斥锁的句柄。 如果由于 pxMutexBuffer 为 NULL 而导致 递归互斥锁未创建,则返回 NULL。
SemaphoreHandle_t xSemaphore = NULL;
StaticSemaphore_t xMutexBuffer;
void vATask( void * pvParameters )
{
/* Create a recursivemutex semaphore without using any dynamic
memory allocation. The mutex's data structures will be saved into
the xMutexBuffer variable. */
xSemaphore = xSemaphoreCreateRecursiveMutexStatic( &xMutexBuffer );
/* The pxMutexBuffer was not NULL, so it is expected that the
handle will not be NULL. */
configASSERT( xSemaphore );
/* Rest of the task code goes here. */
}
void vSemaphoreDelete( SemaphoreHandle_t xSemaphore );
删除信号量,包括互斥锁型信号量和递归信号量。
请勿删除已有阻塞任务的信号量(正在 等待信号灯可用的阻塞状态任务)。
xSemaphore 被删除的信号量的句柄。
semphr. h
TaskHandle_t xSemaphoreGetMutexHolder( SemaphoreHandle_t xMutex );
必须在 FreeRTOSConfig.h 中将 INCLUDE_xSemaphoreGetMutexHolder 设置为 1, 此函数才可用。
返回保存函数参数指定的 MUTEX 的任务的句柄(若有)。
xSemaphoreGetMutexHolder () 可以可靠地用于确定调用任务是否 是互斥锁持有者,但如果由调用任务之外的任务持有互斥锁,则无法可靠地使用 xSemaphoreGetMutexHolder () 。 这是因为 MUTEX 支架可能会 在调用该函数的调用任务与测试该函数返回值之间 更改。
FreeRTOSConfig.h中的configUSE_MUTEXES必须设置为1 ,才能使用xSemaphoreGetMutexHolder ()。
xMutex 正在查询的互斥体的句柄。
Returns:
保存 xMutex 参数指定的 MUTEX 的任务的句柄。 如果在 xMutex 参数中传递的信号量不是 MUTEX 类型的信号量,或者如果 MUTEX 可用,未被任何任务持有,则返回 NULL。
semphr. h
UBaseType_t uxSemaphoreGetCount( SemaphoreHandle_t xSemaphore );
返回信号量计数。
xSemaphore 正在查询的信号量的句柄。
如果信号量是计数信号量,则返回信号量的当前计数值 。 如果信号量是二进制信号量, 则当信号量可用时,返回 1,当信号量不可用时, 返回 0。
提示: 在许多使用场景中,使用直达任务通知要比使用信号量的速度更快,内存效率更高 。
semphr. h
xSemaphoreTake( SemaphoreHandle_t xSemaphore,
TickType_t xTicksToWait );
用于获取信号量的宏。之前必须 通过调用 xSemaphoreCreateBinary()、xSemaphoreCreateMutex() 或 xSemaphoreCreateCounting() 来创建信号量。
不得从 ISR 调用此宏。 必要时可使用 xQueueReceiveFromISR() 从中断内获取信号量,但这并非 常规操作。 信号量使用队列作为其底层机制,因此函数在某种程度上可互操作。
xSemaphore 正在获取的信号量的句柄——在创建信号量时获得。
xTicksToWait 等待信号量变为可用的时间(以滴答为单位)。宏 portTICK_PERIOD_MS 可用于将其转换为实时。可以用一个为零的阻塞时间来轮询信号量。
如果 INCLUDE_vTaskSuspend 设置为 “1” ,则将阻塞时间指定为 portMAX_DELAY 会导致任务无限期地阻塞(没有超时)。
Returns:
如果获得信号量,则返回 pdTRUE;如果 xTicksToWait 过期,信号量不可用,则返回 pdFALSE。
示例用法:
SemaphoreHandle_t xSemaphore = NULL;
/* A task that creates a semaphore. */
void vATask( void * pvParameters )
{
/* Create the semaphore to guard a shared resource. As we are using
the semaphore for mutual exclusion we create a mutex semaphore
rather than a binary semaphore. */
xSemaphore = xSemaphoreCreateMutex();
}
/* A task that uses the semaphore. */
void vAnotherTask( void * pvParameters )
{
/* ... Do other things. */
if( xSemaphore != NULL )
{
/* See if we can obtain the semaphore. If the semaphore is not
available wait 10 ticks to see if it becomes free. */
if( xSemaphoreTake( xSemaphore, ( TickType_t ) 10 ) == pdTRUE )
{
/* We were able to obtain the semaphore and can now access the
shared resource. */
/* ... */
/* We have finished accessing the shared resource. Release the
semaphore. */
xSemaphoreGive( xSemaphore );
}
else
{
/* We could not obtain the semaphore and can therefore not access
the shared resource safely. */
}
}
}
semphr. h
xSemaphoreTakeFromISR
(
SemaphoreHandle_t xSemaphore,
signed BaseType_t *pxHigherPriorityTaskWoken
)
可从 ISR 调用的 xSemaphoreTake() 版本。 与 xSemaphoreTake() 不同,xSemaphoreTakeFromISR() 不允许 指定阻塞时间。
xSemaphore 信号量被“获取”。 信号量由 SemaphoreHandle_t 类型的变量引用,必须在使用之前显式创建。
pxHigherPriorityTaskWoken 信号量可能(尽管不太可能,并且取决于信号量类型)阻塞一个或多个任务,等待给出信号量。 调用 xSemaphoreTakeFromISR() 将使被阻塞的任务等待信号量离开已阻塞状态。 如果调用 API 函数导致任务离开已阻塞状态,并且未阻塞的任务的优先级等于或高于当前正在执行的任务(被中断的任务),则在内部,API 函数会将 *pxHigherPriorityTaskWoken 设置为 pdTRUE。
如果 xSemaphoreTakeFromISR() 将 *pxHigherPriorityTaskWoken 设置为 pdTRUE,则应在退出中断之前执行上下文切换。 这将确保中断直接返回到最高优先级的就绪状态任务。 该机制与 xQueueReceiveFromISR() 函数中使用的机制相同,
从 FreeRTOS V7.3.0 开始,pxHigherPriorityTaskWoken 是一个可选参数,可设置为 NULL。
如果信号量已成功获取,则返回 pdTRUE。 如果信号量因不可用而未成功获取,则返回 pdFALSE。
semphr. h
xSemaphoreTakeRecursive( SemaphoreHandle_t xMutex,
TickType_t xTicksToWait );
递归地获得或“获取”一个互斥锁型信号量的宏。 此互斥锁必须已经事先通过调用 xSemaphoreCreateRecursiveMutex() 完成创建;
必须在 FreeRTOSConfig.h 中将 configUSE_RECURSIVE_MUTEXES 设置为 1, 此宏才可用。
不得在使用 xSemaphoreCreateMutex() 创建的互斥锁上使用此宏。
所有者可以反复“获取”递归使用的互斥锁。在所有者 为每个成功的“获取”请求调用 xSemaphoreGiveRecursive() 之前,该互斥锁不会再次变得可用。 例如, 如果一个任务成功地“获取”了同一个互斥锁 5 次, 那么任何其他任务将无法使用这个互斥锁, 直到任务也正好“给”回了这个互斥锁 5 次为止。
xMutex 正在获得的互斥锁的句柄。 这是由 xSemaphoreCreateRecursiveMutex() 返回的句柄。
xTicksToWait 等待信号量变为可用的时间(以滴答为单位)。 宏 portTICK_PERIOD_MS 可用于将其转换为实时。 可以用一个为零的阻塞时间来轮询信号量。 如果任务已有信号量,则无论 xTicksToWait 的值是多少,xSemaphoreTakeRecursive() 都将立即返回。
如果获得信号量,则返回 pdTRUE。 如果 xTicksToWait 过期,信号量不可用,则返回 pdFALSE。
SemaphoreHandle_t xMutex = NULL;
// A task that creates a mutex.
void vATask( void * pvParameters )
{
// Create the mutex to guard a shared resource.
xMutex = xSemaphoreCreateRecursiveMutex();
}
// A task that uses the mutex.
void vAnotherTask( void * pvParameters )
{
// ... Do other things.
if( xMutex != NULL )
{
// See if we can obtain the mutex. If the mutex is not available
// wait 10 ticks to see if it becomes free.
if( xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 ) == pdTRUE )
{
// We were able to obtain the mutex and can now access the
// shared resource.
// ...
// For some reason due to the nature of the code further calls to
// xSemaphoreTakeRecursive() are made on the same mutex. In real
// code these would not be just sequential calls as this would make
// no sense. Instead the calls are likely to be buried inside
// a more complex call structure.
xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 );
xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 );
// The mutex has now been 'taken' three times, so will not be
// available to another task until it has also been given back
// three times. Again it is unlikely that real code would have
// these calls sequentially, but instead buried in a more complex
// call structure. This is just for illustrative purposes.
xSemaphoreGiveRecursive( xMutex );
xSemaphoreGiveRecursive( xMutex );
xSemaphoreGiveRecursive( xMutex );
// Now the mutex can be taken by other tasks.
}
else
{
// We could not obtain the mutex and can therefore not access
// the shared resource safely.
}
}
}
提示: 在许多使用场景中,使用直达任务通知要比使用信号量的速度更快,内存效率更高 。
semphr. h
xSemaphoreGive( SemaphoreHandle_t xSemaphore );
用于释放信号量的宏。该信号量此前必须 通过调用 xSemaphoreCreateBinary()、xSemaphoreCreateMutex() 或 xSemaphoreCreateCounting() 创建。
不得在 ISR 中使用此宏。
此宏不得用于由 xSemaphoreCreateRecursiveMutex() 创建的信号量。
xSemaphore 要释放的信号量的句柄。这是信号量创建时返回的句柄。
如果信号量释放成功,则返回 pdTRUE;如果发生错误,则返回 pdFALSE。信号量的实现基于队列。发布消息时,如果队列上没有空间,那么可能会发生错误,这表明最初未能正确获取信号量。
SemaphoreHandle_t xSemaphore = NULL;
void vATask( void * pvParameters )
{
// Create the semaphore to guard a shared resource. As we are using
// the semaphore for mutual exclusion we create a mutex semaphore
// rather than a binary semaphore.
xSemaphore = xSemaphoreCreateMutex();
if( xSemaphore != NULL )
{
if( xSemaphoreGive( xSemaphore ) != pdTRUE )
{
// We would expect this call to fail because we cannot give
// a semaphore without first "taking" it!
}
// Obtain the semaphore - don't block if the semaphore is not
// immediately available.
if( xSemaphoreTake( xSemaphore, ( TickType_t ) 0 ) )
{
// We now have the semaphore and can access the shared resource.
// ...
// We have finished accessing the shared resource so can free the
// semaphore.
if( xSemaphoreGive( xSemaphore ) != pdTRUE )
{
// We would not expect this call to fail because we must have
// obtained the semaphore to get here.
}
}
}
}
semphr. h
xSemaphoreGiveRecursive( SemaphoreHandle_t xMutex )
递归地释放或“给出”一个互斥锁型信号量的宏。 此互斥锁必须已经事先通过调用 xSemaphoreCreateRecursiveMutex() 完成创建;
必须在 FreeRTOSConfig.h 中将 configUSE_RECURSIVE_MUTEXES 设置为 1, 此宏才可用。
不得在使用 xSemaphoreCreateMutex() 创建的互斥锁上使用此宏。
所有者可以反复“获取”递归使用的互斥锁。在所有者 为每个成功的“获取”请求调用 xSemaphoreGiveRecursive() 之前,该互斥锁不会再次变得可用。 例如, 如果一个任务成功地“获取”了同一个互斥锁 5 次, 那么任何其他任务将无法使用这个互斥锁, 直到任务也正好“给”回了这个互斥锁 5 次为止。
xMutex 正在释放或“给出”的互斥锁的句柄。 这是由 xSemaphoreCreateRecursiveMutex() 返回的句柄。
如果成功给出信号量,则返回 pdTRUE。
SemaphoreHandle_t xMutex = NULL;
// A task that creates a mutex.
void vATask( void * pvParameters )
{
// Create the mutex to guard a shared resource.
xMutex = xSemaphoreCreateRecursiveMutex();
}
// A task that uses the mutex.
void vAnotherTask( void * pvParameters )
{
// ... Do other things.
if( xMutex != NULL )
{
// See if we can obtain the mutex. If the mutex is not available
// wait 10 ticks to see if it becomes free.
if( xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 ) == pdTRUE )
{
// We were able to obtain the mutex and can now access the
// shared resource.
// ...
// For some reason due to the nature of the code further calls to
// xSemaphoreTakeRecursive() are made on the same mutex. In real
// code these would not be just sequential calls as this would make
// no sense. Instead the calls are likely to be buried inside
// a more complex call structure.
xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 );
xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 );
// The mutex has now been 'taken' three times, so will not be
// available to another task until it has also been given back
// three times. Again it is unlikely that real code would have
// these calls sequentially, it would be more likely that the calls
// to xSemaphoreGiveRecursive() would be called as a call stack
// unwound. This is just for demonstrative purposes.
xSemaphoreGiveRecursive( xMutex );
xSemaphoreGiveRecursive( xMutex );
xSemaphoreGiveRecursive( xMutex );
// Now the mutex can be taken by other tasks.
}
else
{
// We could not obtain the mutex and can therefore not access
// the shared resource safely.
}
}
}
提示: 在许多使用场景中,使用直达任务通知要比使用信号量的速度更快,内存效率更高 。
semphr. h
xSemaphoreGiveFromISR
(
SemaphoreHandle_t xSemaphore,
signed BaseType_t *pxHigherPriorityTaskWoken
)
用于释放信号量的宏。释放前信号量必须已经 通过调用 xSemaphoreCreateBinary() 或 xSemaphoreCreateCounting() 创建。
互斥锁型信号量(那些调用 xSemaphoreCreateMutex() 创建的信号量) 不得与此宏一起使用。
此宏可在 ISR 中使用。
xSemaphore 要释放的信号量的句柄。这是创建信号量时返回的句柄。
pxHigherPriorityTaskWoken 如果释放信号量导致任务解除阻塞,并且解除阻塞的任务的优先级高于当前运行的任务,则 xSemaphoreGiveFromISR() 会将 *pxHigherPriorityTaskWoken 设置为 pdTRUE。 如果 xSemaphoreGiveFromISR() 将此值设置为 pdTRUE ,则应在退出中断之前请求上下文切换。
从 FreeRTOSV7.3.0 开始,pxHigherPriorityTaskWoken 是一个可选参数,可设置为 NULL。
如果成功给出信号量,则返回 pdTRUE,否则 errQUEUE_FULL。
请注意, 使用直达任务通知代替信号量, 通常可以更有效地实现如下所示的功能。
#define LONG_TIME 0xffff
#define TICKS_TO_WAIT 10
SemaphoreHandle_t xSemaphore = NULL;
/* Repetitive task. */
void vATask( void * pvParameters )
{
/* We are using the semaphore for synchronisation so we create a binary
semaphore rather than a mutex. We must make sure that the interrupt
does not attempt to use the semaphore before it is created! */
xSemaphore = xSemaphoreCreateBinary();
for( ;; )
{
/* We want this task to run every 10 ticks of a timer. The semaphore
was created before this task was started.
Block waiting for the semaphore to become available. */
if( xSemaphoreTake( xSemaphore, LONG_TIME ) == pdTRUE )
{
/* It is time to execute. */
...
/* We have finished our task. Return to the top of the loop where
we will block on the semaphore until it is time to execute
again. Note when using the semaphore for synchronisation with an
ISR in this manner there is no need to 'give' the semaphore
back. */
}
}
}
/* Timer ISR */
void vTimerISR( void * pvParameters )
{
static unsigned char ucLocalTickCount = 0;
static signed BaseType_t xHigherPriorityTaskWoken;
/* A timer tick has occurred. */
... Do other time functions.
/* Is it time for vATask() to run? */
xHigherPriorityTaskWoken = pdFALSE;
ucLocalTickCount++;
if( ucLocalTickCount >= TICKS_TO_WAIT )
{
/* Unblock the task by releasing the semaphore. */
xSemaphoreGiveFromISR( xSemaphore, &xHigherPriorityTaskWoken );
/* Reset the count so we release the semaphore again in 10 ticks
time. */
ucLocalTickCount = 0;
}
/* If xHigherPriorityTaskWoken was set to true you
we should yield. The actual macro used here is
port specific. */
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}