让大家按照先后顺序去访问临界区(公共资源)
信号量,互斥量,事件集
一个非负的数值,大家要去get 和 put,当为0时get失败,最大值时65535
struct rt_semaphore
{
struct rt_ipc_object parent; /* 继承自 ipc_object 类 */
rt_uint16_t value; /* 信号量的值 */
};
/* rt_sem_t 是指向 semaphore 结构体的指针类型 */
typedef struct rt_semaphore* rt_sem_t;
感觉好像动态创建
rt_sem_t rt_sem_create(const char *name,
rt_uint32_t value,
rt_uint8_t flag);
参数 | 描述 |
---|---|
name | 信号量名称 |
value | 信号量初始值 |
flag | 信号量标志,它可以取如下数值: RT_IPC_FLAG_FIFO 或 RT_IPC_FLAG_PRIO(标志线程获取信号量的顺序 -先来先到or优先级排序) |
返回 | —— |
RT_NULL | 创建失败 |
信号量的控制块指针 | 创建成功 |
rt_err_t rt_sem_delete(rt_sem_t sem);
参数 | 描述 |
---|---|
sem | rt_sem_create() 创建的信号量对象 |
返回 | —— |
RT_EOK | 删除成功 |
这个不就是静态创建信号量嘛
rt_err_t rt_sem_init(rt_sem_t sem,
const char *name,
rt_uint32_t value,
rt_uint8_t flag)
参数 | 描述 |
---|---|
sem | 信号量对象的句柄 |
name | 信号量名称 |
value | 信号量初始值 |
flag | 信号量标志,它可以取如下数值: RT_IPC_FLAG_FIFO 或 RT_IPC_FLAG_PRIO |
返回 | —— |
RT_EOK | 初始化成功 |
rt_err_t rt_sem_detach(rt_sem_t sem);
参数 | 描述 |
---|---|
sem | 信号量对象的句柄 |
返回 | —— |
RT_EOK | 脱离成功 |
rt_err_t rt_sem_take (rt_sem_t sem, rt_int32_t time);
参数 | 描述 |
---|---|
sem | 信号量对象的句柄 |
time | 指定的等待时间,单位是操作系统时钟节拍(OS Tick) 永久:RT_WAITING_FOREVER |
返回 | —— |
RT_EOK | 成功获得信号量 |
-RT_ETIMEOUT | 超时依然未获得信号量 |
-RT_ERROR | 其他错误 |
rt_err_t rt_sem_trytake(rt_sem_t sem);
只尝试一次,立马返回是否可用
参数 | 描述 |
---|---|
sem | 信号量对象的句柄 |
返回 | —— |
RT_EOK | 成功获得信号量 |
-RT_ETIMEOUT | 获取失败 |
rt_err_t rt_sem_release(rt_sem_t sem);
参数 | 描述 |
---|---|
sem | 信号量对象的句柄 |
返回 | —— |
RT_EOK | 成功释放信号量 |
本质就是特殊的二值(开,闭)信号量,支持递归访问且能防止线程优先级翻转,只能由持有线程释放,信号量谁都可以释放 ,创建时时开锁的状态
当某线程持有时,该线程就拥有所有权,持有线程递归的话也不会被挂起
so 使用场景:
优先级翻转:低优先级线程持有一资源信号量,但是被其他线程抢占,假设最高优先级申请不到该资源,现在的调度情况变成了中优先级或者低优先级先被调度,形成了调度上的优先级翻转
解决方法:1.优先级继承算法: 提高占有资源的低优先级线程的优先级,使有等待资源最高优先级线程的优先级相同,避免线程抢占
struct rt_mutex
{
struct rt_ipc_object parent; /* 继承自 ipc_object 类 */
rt_uint16_t value; /* 互斥量的值 */
rt_uint8_t original_priority; /* 持有线程的原始优先级 */
rt_uint8_t hold; /* 持有线程的持有次数 */
struct rt_thread *owner; /* 当前拥有互斥量的线程 */
};
/* rt_mutext_t 为指向互斥量结构体的指针类型 */
typedef struct rt_mutex* rt_mutex_t;
动态创建:
rt_mutex_t rt_mutex_create (const char* name, rt_uint8_t flag);
参数 | 描述 |
---|---|
name | 互斥量的名称 |
flag | 互斥量标志,它可以取如下数值: RT_IPC_FLAG_FIFO 或 RT_IPC_FLAG_PRIO |
返回 | —— |
互斥量句柄 | 创建成功 |
RT_NULL | 创建失败 |
静态初始化:
rt_err_t rt_mutex_init (rt_mutex_t mutex, const char* name, rt_uint8_t flag);
参数 | 描述 |
---|---|
mutex | 互斥量对象的句柄,它由用户提供,并指向互斥量对象的内存块 |
name | 互斥量的名称 |
flag | 互斥量标志,它可以取如下数值: RT_IPC_FLAG_FIFO 或 RT_IPC_FLAG_PRIO |
返回 | —— |
RT_EOK | 初始化成功 |
动态释放:
rt_err_t rt_mutex_delete (rt_mutex_t mutex);
参数 | 描述 |
---|---|
mutex | 互斥量对象的句柄 |
返回 | —— |
RT_EOK | 删除成功 |
静态脱离:
rt_err_t rt_mutex_detach (rt_mutex_t mutex);
参数 | 描述 |
---|---|
mutex | 互斥量对象的句柄 |
返回 | —— |
RT_EOK | 成功 |
rt_err_t rt_mutex_take (rt_mutex_t mutex, rt_int32_t time);
参数 | 描述 |
---|---|
mutex | 互斥量对象的句柄 |
time | 指定等待的时间 |
返回 | —— |
RT_EOK | 成功获得互斥量 |
-RT_ETIMEOUT | 超时 |
-RT_ERROR | 获取失败 |
rt_err_t rt_mutex_release(rt_mutex_t mutex);
参数 | 描述 |
---|---|
mutex | 互斥量对象的句柄 |
返回 | —— |
RT_EOK | 成功 |
由于包含多个事件,因此可以一对多,多对多;是一个32位无符号整型变量
场景:
特点:
struct rt_event
{
struct rt_ipc_object parent; /* 继承自 ipc_object 类 */
/* 事件集合,每一 bit 表示 1 个事件,bit 位的值可以标记某事件是否发生 */
rt_uint32_t set;
};
/* rt_event_t 是指向事件结构体的指针类型 */
typedef struct rt_event* rt_event_t;
动态创建事件集
rt_event_t rt_event_create(const char* name, rt_uint8_t flag);
参数 | 描述 |
---|---|
name | 事件集的名称 |
flag | 事件集的标志,它可以取如下数值: RT_IPC_FLAG_FIFO 或 RT_IPC_FLAG_PRIO |
返回 | —— |
RT_NULL | 创建失败 |
事件对象的句柄 | 创建成功 |
初始化静态事件集
rt_err_t rt_event_init(rt_event_t event, const char* name, rt_uint8_t flag);
参数 | 描述 |
---|---|
event | 事件集对象的句柄 |
name | 事件集的名称 |
flag | 事件集的标志,它可以取如下数值: RT_IPC_FLAG_FIFO 或 RT_IPC_FLAG_PRIO |
返回 | —— |
RT_EOK | 成功 |
删除动态事件集
rt_err_t rt_event_delete(rt_event_t event);
参数 | 描述 |
---|---|
event | 事件集对象的句柄 |
返回 | —— |
RT_EOK | 成功 |
脱离静态事件集
rt_err_t rt_event_detach(rt_event_t event);
参数 | 描述 |
---|---|
event | 事件集对象的句柄 |
返回 | —— |
RT_EOK | 成功 |
rt_err_t rt_event_send(rt_event_t event, rt_uint32_t set);
参数 | 描述 |
---|---|
event | 事件集对象的句柄 |
set | 发送的一个或多个事件的标志值 |
返回 | —— |
RT_EOK | 成功 |
系统会根据set和option判断接收的事件是否已经发送,如果发生,根据option决定是否擦除,然后返回到接收的线程,如果没有发生,将set和option填入线程本身,线程挂起一段事件等待事件发生
rt_err_t rt_event_recv(rt_event_t event,
rt_uint32_t set,
rt_uint8_t option,
rt_int32_t timeout,
rt_uint32_t* recved);
参数 | 描述 |
---|---|
event | 事件集对象的句柄 |
set | 接收线程感兴趣的事件 |
option | 接收选项 |
timeout | 指定超时时间 |
recved | 指向接收到的事件 |
返回 | —— |
RT_EOK | 成功 |
-RT_ETIMEOUT | 超时 |
-RT_ERROR | 错误 |
option:
/* 选择 逻辑与 或 逻辑或 的方式接收事件 */
RT_EVENT_FLAG_OR
RT_EVENT_FLAG_AND
/* 选择清除重置事件标志位 */
RT_EVENT_FLAG_CLEAR