CMSIS-RTOS2 文档翻译 之 参考(CMSIS-RTOS2 API 之 互斥锁管理)

互斥锁管理
CMSIS-RTOS2 API

使用互斥锁(Mutex)同步资源访问。更多...

数据结构

struct   osMutexAttr_t
  互斥锁的属性结构体。更多...
 

宏定义

#define  osMutexRecursive   0x00000001U
  递归互斥锁。更多...
 
#define  osMutexPrioInherit   0x00000002U
  优先级继承协议。更多...
 
#define  osMutexRobust   0x00000008U
  强健的互斥锁。更多...
 

类型定义

typedef void *  osMutexId_t
 

函数

osMutexId_t  osMutexNew (const osMutexAttr_t *attr)
  创建并初始化一个互斥锁对象。更多...
 
const char *  osMutexGetName (osMutexId_t mutex_id)
  获取互斥锁对象的名称。更多...
 
osStatus_t  osMutexAcquire (osMutexId_t mutex_id, uint32_t timeout)
  如果它被锁定,则获取互斥锁或超时值。更多...
 
osStatus_t  osMutexRelease (osMutexId_t mutex_id)
  释放由 osMutexAcquire 获取的互斥锁。更多...
 
osThreadId_t  osMutexGetOwner (osMutexId_t mutex_id)
  获取拥有互斥锁对象的线程。更多...
 
osStatus_t  osMutexDelete (osMutexId_t mutex_id)
  删除互斥锁对象。更多...
 

描述

相互排斥(广为人知的互斥锁)在各种操作系统中用于资源管理。单片机器件中的许多资源可以重复使用,但一次只能使用一个线程(例如通信通道,内存和文件)。互斥锁用于保护对共享资源的访问。互斥体被创建并在线程之间传递(它们可以获取并释放互斥锁)。

CMSIS-RTOS2 文档翻译 之 参考(CMSIS-RTOS2 API 之 互斥锁管理)_第1张图片
CMSIS-RTOS 互斥锁

互斥量是信号量的特殊版本。像信号量一样,它是一个令牌容器。但是不能拥有多个令牌,互斥量只能携带一个(代表资源)。因此,互斥量令牌是二进制的并且是有界的,即它可以是可用的,也可以是拥有的线程阻塞的。互斥量的优点是它引入了线程所有权。当一个线程获得一个互斥量并成为它的所有者时,从该线程获得的后续互斥量将立即成功,而没有任何延迟(如果指定了 osMutexRecursive)。因此,互斥量获取/释放可以嵌套。

CMSIS-RTOS2 文档翻译 之 参考(CMSIS-RTOS2 API 之 互斥锁管理)_第2张图片
CMSIS-RTOS 互斥锁状态
注意
不能从中断服务程序(ISR)调用互斥锁管理函数,这与可以从 ISR 释放的二进制信号不同。
有关 RTX5 配置选项,请参阅互斥锁配置。

数据结构文档

struct osMutexAttr_t

用于配置互斥锁的属性。

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

  • osMutexAttr_t::cb_mem
  • osMutexAttr_t::cb_size
数据字段
const char * name 互斥锁的名称

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

uint32_t attr_bits 属性位

可以分配以下预定义位掩码来设置互斥锁对象的选项。

位掩码 描述
osMutexRecursive 互斥锁是递归的。
osMutexPrioInherit 优先级继承协议。
osMutexRobust 强健的互斥锁。
void * cb_mem 内存控制块

指向互斥锁控件块对象的内存位置。 这可以选择用于自定义内存管理系统。
默认值:NULL(使用内核内存管理)。

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

内存块的大小与 cb_mem 一起传递。必须是互斥锁控制块对象的大小或更大。

宏定义文档

#define osMutexRecursive   0x00000001U

osMutexAttr_t 中的递归标志。

同一个线程可以多次使用互斥锁,而不会自行锁定。每当拥有的线程获取互斥锁时,锁定计数就会增加。互斥锁必须多次释放,直到锁计数达到零。在达到零时,互斥锁实际上被释放并且可以被其他线程获取。

注意
可能的递归锁的最大数量是实现特定的,即用于锁计数的类型大小。如果递归锁的最大数量耗尽,互斥锁获取可能会失败。

代码示例

#include "cmsis_os2.h"
osMutexId_t mutex_id;
const osMutexAttr_t Thread_Mutex_attr = {
"myThreadMutex", // human readable mutex name
osMutexRecursive, // attr_bits
NULL, // memory for control block
0U // size for control block
};
// must be called from a thread context
void UseMutexRecursively( int count) {
osStatus_t result = osMutexAcquire(mutex_id, osWaitForever); // lock count is incremented, might fail when lock count is depleted
if (result == osOK) {
if (count < 10) {
UseMutexRecursively(count + 1);
}
osMutexRelease(mutex_id); // lock count is decremented, actually releases the mutex on lock count zero
}
}
#define osMutexPrioInherit   0x00000002U

osMutexAttr_t 中的优先级继承标志。

如果拥有者线程优先级较低,则使用优先级继承协议的互斥锁将等待线程优先级转移给当前互斥锁所有者。这确保了低优先级的线程不会阻塞高优先级的线程。

否则,低优先级的线程可能会持有一个互斥锁,但由于另一个中等优先级的线程而未被授予执行时间。没有优先级继承,等待互斥锁的高优先级线程将被中等优先级线程阻塞,称为优先级反转。

代码示例

如果 osMutexPrioInherit 被移除,此示例显示阻塞的高优先级线程。

#include "cmsis_os2.h"
osMutexId_t mutex_id;
const osMutexAttr_t Thread_Mutex_attr = {
"myThreadMutex", // human readable mutex name
osMutexPrioInherit, // attr_bits
NULL, // memory for control block
0U // size for control block
};
void HighPrioThread( void *argument) {
osDelay(1000); // wait 1s until start actual work
while(1) {
osMutexAcquire(mutex_id, osWaitForever); // try to acquire mutex
// do stuff
osMutexRelease(mutex_id);
}
}
void MidPrioThread( void *argument) {
osDelay(1000); // wait 1s until start actual work
while(1) {
// do non blocking stuff
}
}
void LowPrioThread( void *argument) {
while(1) {
osMutexAcquire(mutex_id, osWaitForever);
osDelay(5000); // block mutex for 5s
osMutexRelease(mutex_id);
osDelay(5000); // sleep for 5s
}
}

在第一秒中,高优先级线程和中优先级线程被延迟。因此,低优先级的线程可以开始工作,获得互斥锁和延迟。

在第一秒后,高优先级线程和中优先级线程准备就绪。因此,高优先级线程优先,并尝试获取互斥锁。由于互斥锁已由低优先级线程拥有,因此高优先级线程被阻塞。

最后,中等优先级的线程被执行并开始做很多非阻塞的事情,即它不调用任何阻塞 RTOS 功能。

如果没有 osMutexPrioInherit ,我们会永远卡在这里。即使低优先级线程在5秒后准备就绪。由于其优先级低,中等优先级的线程总是优先。称为优先级倒置的效应导致中等优先级线程间接阻塞高优先级线程。

使用示例代码中显示的 osMutexPrioInherit ,我们摆脱了这种情况。由于优先级继承协议,低优先级线程在持有互斥量的同时继承高优先级。因此,低优先级线程优先于中等优先级线程,直到它释放互斥量。在 osMutexRelease 上,高优先级线程准备就绪,并立即安排。

#define osMutexRobust   0x00000008U

osMutexAttr_t 中的强健标志。

如果拥有的线程终止(由 osThreadExit 或 osThreadTerminate),则强健的互斥锁会自动释放。非强健的互斥锁不会被释放,用户必须手动确保互斥锁释放。

代码示例

如果 osMutexRobust 被移除,这个例子显示一个被阻塞的互斥锁。

#include "cmsis_os2.h"
osMutexId_t mutex_id;
const osMutexAttr_t Thread_Mutex_attr = {
"myThreadMutex", // human readable mutex name
osMutexRobust, // attr_bits
NULL, // memory for control block
0U // size for control block
};
void Thread( void *argument) {
osMutexAcquire(mutex_id, osWaitForever);
osThreadExit();
}

由于 osMutexRobust ,互斥锁会自动释放。一个非鲁棒的互斥锁将保持锁定状态,不能再被释放。

类型定义文档

osMutexId_t

互斥锁 ID 标识互斥锁。

返回者:

  • osMutexNew

函数文档

osMutexId_t osMutexNew ( const osMutexAttr_t *  attr )  
参数
[in] attr 互斥锁属性; NULL:默认值。
返回
互斥锁 ID 用于其他函数的引用,或者在出错时为 NULL 。

函数 osMutexNew 创建并初始化一个新的互斥锁对象,并返回指向互斥锁对象标识符的指针,或者在发生错误时返回 NULL 。它可以在 RTOS 启动之前(调用 osKernelStart)安全地调用,但不能在它初始化之前(调用 osKernelInitialize)调用

参数 attr 设置互斥锁对象属性(请参阅 osMutexAttr_t)。如果设置为 NULL,则会使用默认属性。

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

代码示例

#include "cmsis_os2.h"
osMutexId_t mutex_id;
const osMutexAttr_t Thread_Mutex_attr = {
"myThreadMutex", // human readable mutex name
osMutexRecursive | osMutexPrioInherit, // attr_bits
NULL, // memory for control block
0U // size for control block
};
void CreateMutex ( void) {
mutex_id = osMutexNew(&Thread_Mutex_attr);
if (mutex_id != NULL) {
// Mutex object created
}
}
*const char * osMutexGetName ( osMutexId_t  mutex_id )  
参数
[in] mutex_id 互斥锁 ID 由 osMutexNew 获得。
返回
名称为 NULL 终止的字符串。

函数 osMutexGetName 返回指向由参数 mutex_id 标识的互斥锁的名称字符串的指针,或者在出现错误时返回 NULL 。

注意
该函数不能从中断服务程序调用。
osStatus_t osMutexAcquire ( osMutexId_t  mutex_id,
    uint32_t  timeout 
  )    
参数
[in] mutex_id 互斥锁 ID 由 osMutexNew 获得。
[in] timeout 超时值或 0 在没有超时的情况下。
返回
状态代码,指示该功能的执行状态。

阻塞函数 osMutexAcquire 一直等待,直到由参数 mutex_id 指定的互斥锁对象变为可用。如果没有其他线程获得互斥锁,该函数立即返回并阻塞互斥锁对象。

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

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

可能的 osStatus_t 返回值:

  • osOK: 互斥锁已经获得。
  • osErrorTimeout: 在给定的时间内无法获得互斥锁。
  • osErrorParameter: 参数 mutex_id 是 NULL 或无效。
  • osErrorResource: 由参数 mutex_id 指定的互斥锁处于无效互斥锁状态,或者在未指定超时时无法获得互斥锁。
  • osErrorISR: 不能从中断服务程序调用。
注意
该函数不能从中断服务程序调用。

代码示例

#include "cmsis_os2.h"
void WaitMutex ( void) {
osMutexId_t mutex_id;
osStatus_t status;
mutex_id = osMutexNew(NULL);
if (mutex_id != NULL) {
status = osMutexAcquire(mutex_id, 0);
if (status != osOK) {
// handle failure code
}
}
}
osStatus_t osMutexRelease ( osMutexId_t  mutex_id )  
参数
[in] mutex_id 互斥锁 ID 由 osMutexNew 获得。
返回
状态代码,指示该功能的执行状态。

osMutexRelease 函数释放由参数 mutex_id 指定的互斥锁。当前等待此互斥锁的其他线程将进入 READY 状态。

可能的 osStatus_t 返回值:

  • osOK: 该互斥锁已被正确释放。
  • osErrorParameter: 参数 mutex_id 是 NULL 或无效。
  • osErrorResource: 由参数 mutex_id 指定的互斥锁处于无效互斥锁状态,或者在当前线程不是互斥锁的所有者之前未获得互斥锁。
  • osErrorISR: osMutexRelease 不能从中断服务例程中调用。
注意
该函数不能从中断服务程序调用。

代码示例

#include "cmsis_os2.h"
osMutexId_t mutex_id; // Mutex id populated by the function osMutexNew()
void ReleaseMutex ( osMutexId_t mutex_id) {
osStatus_t status;
if (mutex_id != NULL) {
status = osMutexRelease(mutex_id);
if (status != osOK) {
// handle failure code
}
}
}
osThreadId_t osMutexGetOwner ( osMutexId_t  mutex_id )  
参数
[in] mutex_id 互斥锁 ID 由 osMutexNew 获得。
返回
所有者线程的线程 ID 或 未获取互斥锁时 NULL

函数 osMutexGetOwner 返回获取由参数 mutex_id 指定的互斥锁的线程的线程 ID 。如果发生错误或者互斥锁未被任何线程阻塞,则返回 NULL 。

注意
该函数不能从中断服务程序调用。
osStatus_t osMutexDelete ( osMutexId_t  mutex_id )  
参数
[in] mutex_id 互斥锁 ID 由 osMutexNew 获得。
返回
状态代码,指示该功能的执行状态。

函数 osMutexDelete 删除由参数 mutex_id 指定的互斥锁对象。它释放互斥锁处理获得的内部内存。在这个调用之后,mutex_id 不再有效并且不能使用。可以使用函数 osMutexNew 再次创建互斥锁。

可能的 osStatus_t 返回值:

  • osOK: 该互斥锁对象已被删除。
  • osErrorParameter: 参数 mutex_id 是 NULL 或无效。
  • osErrorResource: 由参数 mutex_id 指定的互斥锁处于无效互斥锁状态。
  • osErrorISR: osMutexDelete 不能从中断服务例程调用。
注意
该函数不能从中断服务程序调用。

代码示例

#include "cmsis_os2.h"
osMutexId_t mutex_id; // Mutex id populated by the function osMutexNew()
void DeleteMutex ( osMutexId_t mutex_id) {
osStatus_t status;
if (mutex_id != NULL) {
status = osMutexDelete(mutex_id);
if (status != osOK) {
// handle failure code
}
}
}

你可能感兴趣的:(CMSIS,CMSIS-RTOS2,文档翻译)