【RT-Thread】线程的同步与通信(IPC机制)

RT-Thread IPC

本文章为RT-Thread5.0.x版本

一、IPC机制

image-20240724202544361

RT-Thread中的IPC可以分成了两大块:

  • 线程同步
  • 线程间通信

二、线程同步

线程同步主要是为了保证多个线程在访问共享资源时的正确性和一致性,避免由于竞争条件导致的数据不一致和程序错误。

线程同步是通过多种机制来实现的,主要包括信号量、互斥量、事件集。

1.信号量

信号量是一种轻型的用于解决线程间同步问题的内核对象,一个或多个运行线程可以获取或释放它,从而达到同步或互斥的目的。用于实现任务与任务之间、任务与中断处理程序之间的同步与互斥。

信号量可以是二值信号量或计数信号量。

  • 二值信号量:顾名思义,只有两个状态,类似于互斥锁,用于确保只有一个线程可以访问共享资源。
  • 计数信号量:用于限制对资源的访问数量。

具体信号量使用的API可以参考文档中心。下面重点讲述信号量的管理机制。

信号量相关接口

a.信号量控制块

image-20240724210750568

b.获取信号量

image-20240724211044023

路径:.\rt-thread\src\ipc.c

这个是获取信号量的API,我们来看一下内部是怎么实现的。

image-20240724211912880

获取信号量可以大致分为这几种情况:

  • 信号量不为0

image-20240724212205065

  • 信号量为0

    • 不等待

    image-20240724212546146

    • 等待

    image-20240724213937574

    image-20240724214312692

    笔者手误了,这边应该是把线程从就绪链表中移除,并添加到信号量的挂起链表,当有信号量释放的时候,就会判断挂起链表中是否有线程,并把其他变为就绪链表。(为什么不重新打就是因为懒,qq截图不能直接重新编辑,不知道有什么比较好的工具)

    线程的超时回调函数

    image-20240724214054167

c.释放信号量

路径:.\rt-thread\src\ipc.c

image-20240724221007184

路径:.\rt-thread\src\ipc.c

image-20240724221513151

路径:.\rt-thread\src\scheduler_comm.c

image-20240724221811800

如果在等待时间内的想获取信号量的线程就会被重新调度。

2.互斥量

互斥量又叫相互排斥的信号量,是一种特殊的二值信号量。互斥量类似于只有一个车位的停车场:当有一辆车进入的时候,将停车场大门锁住,其他车辆在外面等候。当里面的车出来时,将停车场大门打开,下一辆车才可以进入。

互斥量与信号量不同的点:

  • 只能由持有线程释放
  • 解决线程优先级翻转问题(会将持有线程优先级提高跟等待线程一样)

重点看一下互斥量是怎么解决优先级翻转问题的。

互斥量相关接口

a.互斥量控制块

路径:.\rt-thread\src\ipc.c

image-20240724222511208

路径:.\rt-thread\include\rtdef.h

image-20240724224623138

b.获取互斥量

image-20240724233418934

路径:.\rt-thread\src\ipc.c

image-20240724230443967

获取互斥量可以分成这几种情况:

  • 拥有者
    • hold++

image-20240724231014144

  • 不是拥有者

    • 互斥量还未被拥有

    image-20240724232013121

    • 互斥量已经被拥有

      • 不等待

      image-20240724233914775

      • 等待

        将线程移至互斥量的挂起链表,并设置亮着为互斥对象,以及判断是否比当前挂起的线程中优先级高

      image-20240724234442936

      设置定时器,发起调度。

      image-20240724234934057

      image-20240724235653165

c.释放互斥量

路径:.\rt-thread\src\ipc.c

rt_err_t rt_mutex_release(rt_mutex_t mutex)

释放信号量大致可以分为这几种情况:

  • 不是拥有着

image-20240725132933467

  • 是拥有着且拥有的互斥锁为0

    • 没有其他线程想获取互斥量

    image-20240725134714657

    • 有其他线程想获取互斥量

image-20240725134537569

image-20240725135256987

3.事件集

事件集用于线程之间的事件通知和同步。一个事件集包含多个事件标志,线程可以等待一个或多个事件标志。

至于API参考官方文档

事件相关接口

a.事件集控制块

路劲:rt-thread\include\rtdef.h

image-20240725131539502

b.接收事件

路径:.\rt-thread\src\ipc.c

image-20240725172802964

image-20240725173127850

  • 接收成功

image-20240725173441425

  • 接收不成功

    • 不等待

    image-20240725173605897

    • 等待

    image-20240725173821148

    image-20240725174002779

c.发送事件

路径:rt-thread\src\ipc.c

image-20240725174450872

  • 是否有线程挂起

image-20240725175250211

三、线程间的通信

在裸机编程中,经常会使用全局变量进行功能间的通信,如某些功能可能由于一些操作而改变全局变量的值,另一个功能对此全局变量进行读取,根据读取到的全局变量值执行相应的动作,达到通信协作的目的。RT-Thread 中则提供了更多的工具帮助在不同的线程中间传递信息。

1.邮箱

邮箱用于在线程之间传递固定大小的消息。每次发送和接收的消息大小都是固定的。邮箱适用于需要简单、高效传递固定大小数据的场景。

a.邮箱控制块

路径:.\rt-thread\include\rtdef.h

image-20240725181054128

image-20240725202726514

b.接收邮箱

路径:.\rt-thread\src\ipc.c

image-20240725181326801

接收邮箱可以大致分为这几种情况:

  • 没有邮箱且不等待

image-20240725181929529

image-20240725182808872

  • 没有邮箱且等待

image-20240725201137351

image-20240725201232969

image-20240725201405991

c.发送邮箱

路径:.\rt-thread\src\ipc.c

image-20240725201512602

  • 满了不等待

image-20240725201831043

  • 满了等待

image-20240725202018130

  • 成功发送邮箱

image-20240725202256438

2.消息队列

消息队列用于在线程之间传递可变大小的消息,可以设置消息的优先级。消息队列适用于需要传递不同大小数据和具有优先级调度需求的场景。

邮箱队列的机制跟邮箱大致一样,不同的是两者可以传递的消息大小不一样。

  • 11
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值