rt-thread学习3 - 线程间同步

rt-thread学习3 - 线程间同步

            • 同步释义:
            • 术(方式):
        • 1. 信号量:
            • 管理方式:
            • 创建信号量
            • 删除信号量
            • 初始化信号量
            • 脱离信号量
            • 获取信号量
            • 释放信号量
          • 用途:
          • 2. 互斥量
            • 管理方法:
            • 1. 创建互斥量:
            • 2. 删除互斥量
            • 3. 获取互斥量
            • 4. 释放互斥量
          • 3. 事件集
            • 管理方式
            • 1.创建事件集
            • 2.删除事件集
            • 3. 发送事件
            • 4. 接收事件

同步释义:

让大家按照先后顺序去访问临界区(公共资源)

术(方式):

信号量,互斥量,事件集

1. 信号量:

一个非负的数值,大家要去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-thread学习3 - 线程间同步_第1张图片

创建信号量

感觉好像动态创建

 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 成功释放信号量
用途:
  1. 锁(二值信号量)
  2. 中断通知位
  3. 资源计数
2. 互斥量

本质就是特殊的二值(开,闭)信号量,支持递归访问且能防止线程优先级翻转,只能由持有线程释放,信号量谁都可以释放 ,创建时时开锁的状态

当某线程持有时,该线程就拥有所有权,持有线程递归的话也不会被挂起

so 使用场景:

  1. 线程递归造成死锁
  2. 优先级翻转

优先级翻转:低优先级线程持有一资源信号量,但是被其他线程抢占,假设最高优先级申请不到该资源,现在的调度情况变成了中优先级或者低优先级先被调度,形成了调度上的优先级翻转

解决方法: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-thread学习3 - 线程间同步_第2张图片

1. 创建互斥量:

动态创建:

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 初始化成功
2. 删除互斥量

动态释放:

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 成功
3. 获取互斥量
rt_err_t rt_mutex_take (rt_mutex_t mutex, rt_int32_t time);
参数 描述
mutex 互斥量对象的句柄
time 指定等待的时间
返回 ——
RT_EOK 成功获得互斥量
-RT_ETIMEOUT 超时
-RT_ERROR 获取失败
4. 释放互斥量
rt_err_t rt_mutex_release(rt_mutex_t mutex);
参数 描述
mutex 互斥量对象的句柄
返回 ——
RT_EOK 成功
3. 事件集

由于包含多个事件,因此可以一对多,多对多;是一个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-thread学习3 - 线程间同步_第3张图片

1.创建事件集

动态创建事件集

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 成功
2.删除事件集

删除动态事件集

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 成功
3. 发送事件
rt_err_t rt_event_send(rt_event_t event, rt_uint32_t set);
参数 描述
event 事件集对象的句柄
set 发送的一个或多个事件的标志值
返回 ——
RT_EOK 成功
4. 接收事件

系统会根据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

你可能感兴趣的:(rt-thread,操作系统,rtos)