CMSIS-RTOS2 文档翻译 之 参考(CMSIS-RTOS2 API 之 信号量)

信号量

同时从不同线程访问共享资源。更多...

数据结构

struct   osSemaphoreAttr_t
  信号量的属性结构体。 更多...
 

类型定义

typedef void *  osSemaphoreId_t
 

函数

osSemaphoreId_t  osSemaphoreNew (uint32_t max_count, uint32_t initial_count, const osSemaphoreAttr_t *attr)
  创建并初始化信号量对象。更多...
 
const char *  osSemaphoreGetName (osSemaphoreId_t semaphore_id)
  获取信号量对象的名称。更多...
 
osStatus_t  osSemaphoreAcquire (osSemaphoreId_t semaphore_id, uint32_t timeout)
  如果没有令牌可用,则获取信号量标记或超时。更多...
 
osStatus_t  osSemaphoreRelease (osSemaphoreId_t semaphore_id)
  释放一个信号量令牌直到最初的最大数量。更多...
 
uint32_t  osSemaphoreGetCount (osSemaphoreId_t semaphore_id)
  获取当前的信号量令牌计数。更多...
 
osStatus_t  osSemaphoreDelete (osSemaphoreId_t semaphore_id)
  删除一个信号量对象。更多...
 

描述

信号量用于管理和保护对共享资源的访问。信号量与互斥锁非常相似。尽管互斥锁允许一次只有一个线程访问共享资源,但信号量可用于允许固定数量的线程/ ISR 访问共享资源池。使用信号量可以管理对一组相同外设的访问(例如多个 DMA 通道)。

CMSIS-RTOS 信号量

信号量对象应初始化为可用令牌的最大数量。这个可用资源的数量被指定为 osSemaphoreNew 函数的参数。每次使用 osSemaphoreAcquire(处于可用状态)获得信号量标记时,信号量计数递减。当信号量计数为 0(即耗尽状态)时,不能获得更多的信号量标记。尝试获取信号量标记的线程/ISR 需要等待,直到下一个标记为空。信号量与 osSemaphoreRelease 一起发布,增加信号量计数。

CMSIS-RTOS 信号量状态
注意
可以从中断服务例程调用函数 osSemaphoreAcquire ,osSemaphoreGetCount 和 osSemaphoreRelease 。
有关 RTX5 配置选项,请参阅信号量配置。

信号量用例

由于其灵活性,信号量涵盖了广泛的同步应用程序。同时,它们也许是要了解的最具挑战性的 RTOS 对象。下面解释一下信号量的用例,取自 Allen B . Downey 的小信号小册子,该小册子可以免费下载。

非二制信号量(复用)

多路复用限制了可以访问代码的关键部分的线程数量。例如,这可能是访问只支持有限数量的呼叫的 DMA 资源的函数。

要允许多个线程运行该函数,请将信号量初始化为可允许的最大线程数。信号量中的令牌数表示可能输入的附加线程的数量。如果这个数字为零,那么下一个尝试访问该函数的线程将不得不等待,直到其他线程退出并释放其令牌。当所有线程退出时,令牌编号返回 n 。以下示例显示了可能访问该资源的其中一个线程的代码:

osSemaphoreId_t multiplex_id;
void thread_n ( void)
{
multiplex_id = osSemaphoreNew(3, 3, NULL);
while(1)
{
// do something
osSemaphoreRelease(multiplex_id);
}
}

生产者/消费者信号量

生产者 - 消费者问题可以使用两个信号量来解决。

第一个信号量(empty_id)对可用(空)缓冲区进行倒计数,即生产者线程可以通过从这个缓冲区获取可用缓冲区时隙。

第二个信号量(filled_id)对使用过的(填充的)缓冲区进行计数,即消费者线程可以通过从这个缓冲区获取可用数据来等待。

线程在给定序列中获取和释放两个信号量的正确行为是至关重要的。根据这个例子,可以有多个生产者和/或消费者线程同时运行。

#define BUFFER_SIZE 10
osSemaphoreId_t empty_id = osSemaphoreNew(BUFFER_SIZE, BUFFER_SIZE, NULL);
osSemaphoreId_t filled_id = osSemaphoreNew(BUFFER_SIZE, 0, NULL);
void producer_thread ( void)
{
while(1)
{
// produce data
osSemaphoreRelease(filled_id);
}
}
void consumer_thread ( void)
{
while(1)
{
// consume data
osSemaphoreRelease(empty_id);
}
}

数据结构文档

struct osSemaphoreAttr_t

用于配置信号量的属性。

有关使用的详细信息,请参阅内存管理

Data Fields
const char * name 信号量的名称

指向具有人类可读名称的信号量对象的字符串。
默认值:NULL 。

uint32_t attr_bits 属性位

保留以供将来使用(设为'0')。
默认值:0 。

void * cb_mem 内存控制块

指向信号量控制块对象的内存位置的指针。这可以选择用于自定义内存管理系统。
默认值:NULL(使用内核内存管理)。

uint32_t cb_size 为控制块提供的内存大小

内存块的大小与 cb_mem 一起传递。必须是信号量控制块对象的大小或更大。

类型定义文档

信号量标识标识信号量。

返回者:

函数文档

osSemaphoreId_t osSemaphoreNew ( uint32_t  max_count,
    uint32_t  initial_count,
    const osSemaphoreAttr_t attr 
  )    
参数
[in] max_count 可用令牌的最大数量。
[in] initial_count 可用令牌的初始数量。
[in] attr 信号量属性; NULL:默认值。
返回
信号标识以供其他功能参考,或者在发生错误时使用 NULL 。

osSemaphoreNew 函数创建并初始化一个信号量对象,该对象用于管理对共享资源的访问,并返回指向信号量对象标识符的指针或在发生错误时返回 NULL 。它可以在 RTOS 启动之前(调用 osKernelStart)安全地调用,但不能在它初始化之前(调用 osKernelInitialize)调用

参数 max_count 指定可用令牌的最大数量。max_count 值为 1 会创建一个二制信号量。

参数 initial_count 设置可用令牌的初始数量。

参数 attr 指定了额外的信号量属性。如果设置为 NULL ,则会使用默认属性。

注意
该函数不能从中断服务程序调用。

代码示例

#include "cmsis_os2.h" // CMSIS RTOS header file
void Thread_Semaphore ( void *argument); // thread function
osThreadId_t tid_Thread_Semaphore; // thread id
osSemaphoreId_t sid_Thread_Semaphore; // semaphore id
int Init_Semaphore ( void)
{
sid_Thread_Semaphore = osSemaphoreNew(2, 2, NULL);
if (!sid_Thread_Semaphore) {
; // Semaphore object not created, handle failure
}
tid_Thread_Semaphore = osThreadNew (Thread_Semaphore, NULL, NULL);
if (!tid_Thread_Semaphore) {
return(-1);
}
return(0);
}
void Thread_Semaphore ( void *argument)
{
osStatus_t val;
while (1) {
; // Insert thread code here...
val = osSemaphoreAcquire (sid_Thread_Semaphore, 10); // wait for max. 10 ticks for semaphore token to get available
switch (val) {
case osOK:
; // Use protected code here...
osSemaphoreRelease (sid_Thread_Semaphore); // Return a token back to a semaphore
break;
break;
break;
default:
break;
}
osThreadYield (); // suspend thread
}
}
const char * osSemaphoreGetName ( osSemaphoreId_t  semaphore_id )  
参数
[in] semaphore_id 由 osSemaphoreNew 获得的信号量 ID 。
返回
名称为 NULL 终止的字符串。

函数 osSemaphoreGetName 返回指向由参数 semaphore_id 标识的信号量的名称字符串的指针,或者在出现错误时返回 NULL 。

注意
该函数不能从中断服务程序调用。
osStatus_t osSemaphoreAcquire ( osSemaphoreId_t  semaphore_id,
    uint32_t  timeout 
  )    
参数
[in] semaphore_id 由 osSemaphoreNew 获得的信号量 ID 。
[in] timeout 超时值或 0 在没有超时的情况下。
返回
状态代码,指示该函数的执行状态。

阻塞函数 osSemaphoreAcquire 一直等待,直到由参数 semaphore_id 指定的信号量对象的标记变为可用。如果令牌可用,该函数立即返回并减少令牌计数。

参数超时指定系统等待获取令牌的时间。系统等待时,调用此函数的线程将进入 BLOCKED 状态。参数超时可以有以下值:

  • 当超时为 0 时,函数立即返回(即尝试语义)。
  • 当超时设置为 osWaitForever 时,函数将等待无限的时间,直到信号量变为可用(即等待语义)。
  • 所有其他值都指定了内核中的超时时间(即定时等待语义)。

可能的 osStatus_t 返回值:

  • osOK: 该令牌已被获得。
  • osErrorTimeout: 在给定的时间内无法获得令牌。
  • osErrorResource: 未指定超时时无法获取令牌。
  • osErrorParameter: 参数 semaphore_id 不正确。
注意
如果参数 timeout 设置为 0 ,可以从中断服务例程调用。

代码示例

请参阅 osSemaphoreNew 。

osStatus_t osSemaphoreRelease ( osSemaphoreId_t  semaphore_id )  
参数
[in] semaphore_id 由 osSemaphoreNew 获得的信号量 ID 。
返回
状态代码,指示该函数的执行状态。

函数 osSemaphoreRelease 释放由参数 semaphore_id 指定的信号量对象的标记。令牌只能在创建时指定的最大数量发布,请参阅 osSemaphoreNew 。 当前等待此信号量对象标记的其他线程将被置于 READY 状态。

可能的 osStatus_t 返回值:

  • osOK: 令牌已被正确释放并且计数增加。
  • osErrorResource: 已达到最大令牌计数。
  • osErrorParameter: 参数 semaphore_id 不正确。
注意
这个函数可以从中断服务程序中调用。

代码示例

请参阅 osSemaphoreNew 。

uint32_t osSemaphoreGetCount ( osSemaphoreId_t  semaphore_id )  
参数
[in] semaphore_id 由 osSemaphoreNew 获得的信号量 ID 。
返回
可用的令牌数量。

函数 osSemaphoreGetCount 返回由参数 semaphore_id 指定的信号量对象的可用令牌的数量。如果发生错误,则返回 0 。

注意
这个函数可以从中断服务程序中调用。
osStatus_t osSemaphoreDelete ( osSemaphoreId_t  semaphore_id )  
参数
[in] semaphore_id 由 osSemaphoreNew 获得的信号量 ID 。
返回
状态代码,指示该函数的执行状态。

函数 osSemaphoreDelete 删除由参数 semaphore_id 指定的信号量对象。它释放信号量处理获得的内部内存。在这次调用之后,semaphore_id 不再有效并且不能使用。可以使用函数 osSemaphoreNew 再次创建信号量。

可能的 osStatus_t 返回值:

  • osOK: 信号量对象已被删除。
  • osErrorParameter: 参数 semaphore_id 是 NULL 或无效的。
  • osErrorResource: 由参数 semaphore_id 指定的信号量处于无效信号量状态。
  • osErrorISR: osSemaphoreDelete 不能从中断服务程序调用。
注意
该函数不能从中断服务程序调用。

猜你喜欢

转载自blog.csdn.net/u012325601/article/details/80172761