当前位置 : 主页 > 编程语言 > 其它开发 >

RT-Thread线程同步与线程通信

来源:互联网 收集:自由互联 发布时间:2022-06-29
一、线程同步 线程同步的使用场景 例如一项工作中的两个线程:一个线程从传感器中接收数据并且将数据写到共享内存中,同时另一个线程周期性的从共享内存中读取数据并发送去显
一、线程同步
  • 线程同步的使用场景
    例如一项工作中的两个线程:一个线程从传感器中接收数据并且将数据写到共享内存中,同时另一个线程周期性的从共享内存中读取数据并发送去显示,下图描述了两个线程间的数据传递:

  • 临界区
    多个线程操作 / 访问同一块区域(代码),这块代码就称为临界区,上述例子中的共享内存块就是临界区。

    线程互斥是指对于临界区资源访问的排它性。当多个线程都要使用临界区资源时,任何时刻最多只允许一个线程去使用,其它要使用该资源的线程必须等待,直到占用资源者释放该资源。线程互斥可以看成是一种特殊的线程同步。

  • 线程同步的作用
    简单来说RT-Thread的信号量(semaphore)、互斥量(mutex)、和事件集(event)的作用都是保证共享内存的互斥性。

  • 线程之外的临界区使用

    调用 rt_enter_critical() 进入临界区,调用 rt_exit_critical() 退出临界区;

    调用 rt_hw_interrupt_disable() 进入临界区,调用 rt_hw_interrupt_enable() 退出临界区。(关闭全局中断)

  • rt_enter_critical()的使用场景
    在重定义rt_hw_console_output函数的时候会使用临界区,主要是防止在线程中打印信息时,被高优先级的线程抢占,导致打印信息的异常发生,如下图所示:

信号量

  • 信号量的使用:
    简单来说:信号量时是一个非负数的标识,当信号量大于零时,可以rt_sem_take函数获得信号量,获取信号量后会将标识减 1 而释放信号的过程,便是将标识加1

    注意: rt_sem_take函数无法获取信号时,此线程将挂起等待一段时间,或者永久等待。

  • 信号量的互斥使用
    其实互斥量也是信号量的一种,当信号量值始终在 1 和 0 之间变动时,便可实现锁的功能。

互斥量

互斥量又叫相互排斥的信号量,是一种特殊的二值信号量。

  • 互斥量的使用场景
    互斥量的使用比较单一,因为它是信号量的一种,并且它是以锁的形式存在。在初始化的时候,互斥量永远都处于开锁的状态,而被线程持有的时候则立刻转为闭锁的状态。互斥量更适合于:
    • 线程多次持有互斥量的情况下。这样可以避免同一线程多次递归持有而造成死锁的问题。

    • 可能会由于多线程同步而造成优先级翻转的情况。

事件集

事件集与信号量不同,它的特点是可以实现一对多,多对多的同步。集合可以用一个 32 位无符号整型变量来表示,变量的每一位代表一个事件,线程通过 “逻辑与” 或“逻辑或”将一个或多个事件关联起来,形成事件组合。

注意:如果信息标记同时设置了清除标记位,则当线程 #1 唤醒后将主动把事件 1 和事件 30 清为零,否则事件标志将依然存在(即置 1)。

线程优先级翻转

上面说到,互斥量是信号量的一种,那么为啥还要设计互斥量了,当使用信号量实现锁功能的时候,线程执行的图片如下所示:

注意:从图上可以看出,假设执行到A线成时,无法获取到锁,那么A线程将进入等待状态,并不会被挂起,所以通过信号量实现锁是比较浪费资源的。

那么在使用互斥量会发生什么样的现象,当线程 C 先持有互斥量,而后线程 B 试图持有互斥量,此时线程 3 的优先级被零时提升为和线程 2 的优先级相同。所释放后,线程C将回到原有的优先级

二、线程通信

上面的线程同步中通过信号量、互斥量、事件集的实现保护临界区实现线程中的通信,但是这样的操作会使逻辑变得很复杂,所以RT-Thread提供了线程通信,将线程同步与线程通信的使用场景分开。

邮箱

  • 邮箱的使用场合
    邮箱是一种简单的线程间消息传递方式,特点是开销比较低,效率较高。在 RT-Thread 操作系统的实现中能够一次传递一个 4 字节大小的邮件,并且邮箱具备一定的存储功能,能够缓存一定数量的邮件数 (邮件数由创建、初始化邮箱时指定的容量决定)。邮箱中一封邮件的最大长度是 4 字节,所以邮箱能够用于不超过 4 字节的消息传递。

    注意:因为邮箱一次传递的信息最大长度是 4 字节,所以邮箱很少用于传递实际的信息,都是通过传递信息存放的地址。

消息队列

消息队列是另一种常用的线程间通讯方式,是邮箱的扩展。可以应用在多种场合:线程间的消息交换、使用串口接收不定长数据等。

  • 消息队列的使用场合
    消息队列可以应用于发送不定长消息的场合,包括线程与线程间的消息交换,以及中断服务例程中给线程发送消息(中断服务例程不能接收消息)。下面分发送消息和同步消息两部分来介绍消息队列的使用。

    注意:当创建的是一个所有消息的最大长度是 4 字节的消息队列时,消息队列对象将蜕化成邮箱。

信号

信号(又称为软中断信号),在软件层次上是对中断机制的一种模拟,在原理上,一个线程收到一个信号与处理器收到一个中断请求可以说是类似的。

如本博客的内容侵犯了你的权益,请与以下地址联系,本人获知后,马上删除。同时本人深表歉意,并致以崇高的谢意! computer_wx@foxmail.com
网友评论