0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

裸机中环形队列与RTOS中消息队列有何区别呢?

lilihe92 来源:strongerHuang 2024-01-26 09:38 次阅读

正文

环形队列”和“消息队列”在嵌入式领域有应用非常广泛,相信有经验的嵌入式软件工程师对它们都不陌生。 但经常看到一些初学者问一些相关的问题,今天就来分享一下关于“环形队列”和“消息队列”的内容。

1

环形队列

环形队列是在实际编程极为有用的数据结构,它是一个首尾相连的FIFO的数据结构,采用数组的线性空间,数据组织简单,能很快知道队列是否满为空,能以很快速度的来存取数据。

环形队列通常用于通信领域,比如UARTUSBCAN网络等。

1.环形队列实现原理

内存上没有环形的结构,因此环形队列实上是数组的线性空间来实现。当数据到了尾部它将转回到0位置来处理。 因此环列队列的逻辑:将数组元素q[0]与q[MAXN-1]连接,形成一个存放队列的环形空间。

为了方便读写,还要用数组下标来指明队列的读写位置。head/tail.其中head指向可以读的位置,tail指向可以写的位置。

6fd07c00-bb88-11ee-8b88-92fbcf53809c.jpg

环形队列的关键是判断队列为空,还是为满。当tail追上head时,队列为满时;当head追上tail时,队列为空。但如何知道谁追上谁,还需要一些辅助的手段来判断. 如何判断环形队列为空,为满有两种判断方法:

a.附加一个标志位tag

当head赶上tail,队列空,则令tag=0

当tail赶上head,队列满,则令tag=1

b.限制tail赶上head,即队尾结点与队首结点之间至少留有一个元素的空间。

队列空: head==tail

队列满: (tail+1)% MAXN ==head

2.附加标志实现原理 a.采用第一个环形队列有如下结构:

typedef struct ringq{
   int head; /* 头部,出队列方向*/
   int tail; /* 尾部,入队列方向*/ 
   int tag ;
   int size ; /* 队列总尺寸 */
   int space[RINGQ_MAX]; /* 队列空间 */
}RINGQ;

初始化状态:

q->head = q->tail = q->tag = 0;

队列为空:

( q->head == q->tail) && (q->tag == 0)

队列为满 :

 ((q->head == q->tail) && (q->tag == 1))

入队操作,如队列不满,则写入:

q->tail =  (q->tail + 1) % q->size ;

出队操作,如果队列不空,则从head处读出。

下一个可读的位置在:

q->head =  (q->head + 1) % q->size
b.完整代码 头文件ringq.h:
#ifndef __RINGQ_H__
#define __RINGQ_H__


#ifdef __cplusplus
extern "C" {
#endif 


#define QUEUE_MAX 20


typedef struct ringq{
   int head; /* 头部,出队列方向*/
   int tail; /* 尾部,入队列方向*/ 
   int tag ; /* 为空还是为满的标志位*/
    int size ; /* 队列总尺寸 */
   int space[QUEUE_MAX]; /* 队列空间 */
}RINGQ;


/* 
  第一种设计方法:
     当head == tail 时,tag = 0 为空,等于 = 1 为满。
*/


extern int ringq_init(RINGQ * p_queue);


extern int ringq_free(RINGQ * p_queue);




/* 加入数据到队列 */
extern int ringq_push(RINGQ * p_queue,int data);


/* 从队列取数据 */
extern int ringq_poll(RINGQ * p_queue,int *p_data);




#define ringq_is_empty(q) ( (q->head == q->tail) && (q->tag == 0))


#define ringq_is_full(q) ( (q->head == q->tail) && (q->tag == 1))


#define print_ringq(q) printf("ring head %d,tail %d,tag %d
", q->head,q->tail,q->tag);
#ifdef __cplusplus
}
#endif 


#endif /* __RINGQ_H__ */
源代码 ringq.c:
#include 
#include "ringq.h"


int ringq_init(RINGQ * p_queue)
{
   p_queue->size = QUEUE_MAX ;


   p_queue->head = 0;
   p_queue->tail = 0;


   p_queue->tag = 0;


   return 0;
}


int ringq_free(RINGQ * p_queue)
{
  return 0;
}




int ringq_push(RINGQ * p_queue,int data)
{
  print_ringq(p_queue);


  if(ringq_is_full(p_queue))
   {


     printf("ringq is full
");
     return -1;
   }


   p_queue->space[p_queue->tail] = data;


   p_queue->tail = (p_queue->tail + 1) % p_queue->size ;


   /* 这个时候一定队列满了*/
   if(p_queue->tail == p_queue->head)
    {
       p_queue->tag = 1;
    }


    return p_queue->tag ;  
}


int ringq_poll(RINGQ * p_queue,int * p_data)
{
   print_ringq(p_queue);
  if(ringq_is_empty(p_queue))
   {


      printf("ringq is empty
");
     return -1;
   }


   *p_data = p_queue->space[p_queue->head];


   p_queue->head = (p_queue->head + 1) % p_queue->size ;


    /* 这个时候一定队列空了*/
   if(p_queue->tail == p_queue->head)
    {
       p_queue->tag = 0;
    }    
    return p_queue->tag ;
}
看到源代码,相信大家就明白其中原理了。其实还有不采用tag,或者其他一些标志的方法,这里就不进一步展开讲述了,感兴趣的读者可以自行研究一下。

2

消息队列

RTOS中基本都有消息队列这个组件,也是使用最常见的组件之一。

1.消息队列的基本概念

消息队列是一种常用于任务间通信的数据结构,队列可以在任务与任务间、中断和任务间传递信息,实现了任务接收来自其他任务或中断的不固定长度的消息。

通过消息队列服务,任务或中断服务程序可以将一条或多条消息放入消息队列中。同样,一个或多个任务可以从消息队列中获得消息。 使用消息队列数据结构可以实现任务异步通信工作。

2.消息队列的特性

RTOS

消息队列,常见特性:

消息支持先进先出方式排队,支持异步读写工作方式。

读写队列均支持超时机制。

消息支持后进先出方式排队,往队首发送消息(LIFO)。

可以允许不同长度(不超过队列节点最大值)的任意类型消息。

一个任务能够从任意一个消息队列接收和发送消息。

多个任务能够从同一个消息队列接收和发送消息。

当队列使用结束后,可以通过删除队列函数进行删除。

3.消息队列的原理

这里以 FreeRTOS 为例进行说明。FreeRTOS 的消息队列控制块由多个元素组成,当消息队列被创建时,系统会为控制块分配对应的内存空间,用于保存消息队列的一些信息如消息的存储位置,头指针 pcHead、尾指针 pcTail、消息大小 uxItemSize 以及队列长度 uxLength 等

6fd3e9bc-bb88-11ee-8b88-92fbcf53809c.png

比如创建消息队列:

xQueue = xQueueCreate(QUEUE_LEN, QUEUE_SIZE);
任务或者中断服务程序都可以给消息队列发送消息,当发送消息时,如果队列未满或者允许覆盖入队,FreeRTOS 会将消息拷贝到消息队列队尾,否则,会根据用户指定的阻塞超时时间进行阻塞,在这段时间中,如果队列一直不允许入队,该任务将保持阻塞状态以等待队列允许入队。

当其它任务从其等待的队列中读取入了数据(队列未满),该任务将自动由阻塞态转移为就绪态。

当等待的时间超过了指定的阻塞时间,即使队列中还不允许入队,任务也会自动从阻塞态转移为就绪态,此时发送消息的任务或者中断程序会收到一个错误码 errQUEUE_FULL。

发送紧急消息的过程与发送消息几乎一样,唯一的不同是,当发送紧急消息时, 发送的位置是消息队列队头而非队尾,这样,接收者就能够优先接收到紧急消息,从而及时进行消息处理。

当某个任务试图读一个队列时,其可以指定一个阻塞超时时间。

在这段时间中,如果队列为空,该任务将保持阻塞状态以等待队列数据有效。当其它任务或中断服务程序往其等待的队列中写入了数据,该任务将自动由阻塞态转移为就绪态。

当等待的时间超过了指定的阻塞时间,即使队列中尚无有效数据,任务也会自动从阻塞态转移为就绪态。

当消息队列不再被使用时,应该删除它以释放系统资源,一旦操作完成, 消息队列将被永久性的删除。

消息队列的运作过程具体见下图:

6fe6df7c-bb88-11ee-8b88-92fbcf53809c.png

4.消息队列的阻塞机制

出队阻塞:当且仅当消息队列有数据的时候,任务才能读取到数据,可以指定等待数据的阻塞时间。

入队阻塞:当且仅当队列允许入队的时候,发送者才能成功发送消息;队列中无可用消息空间时,说明消息队列已满,此时,系统会根据用户指定的阻塞超时时间将任务阻塞。 假如有多个任务阻塞在一个消息队列中,那么这些阻塞的任务将按照任务优先级进行排序,优先级高的任务将优先获得队列的访问权。

3

环形队列与消息队列的异同

通过以上分析,你会发现“环形队列”和“消息队列”之间有很多共同点:

1.他们都是一种数据结构,结构中都包含头、尾、标志等信息;

2.它们都是分配一块连续的内存空间,且都可以分配多个队列。

3.应用场景类似,有大量吞吐数据的情况下,比如通信领域。

... 当然,他们也有一些不同点:

1.“环形队列”可以独立使用,也可以结合操作系统使用。而消息队列依赖RTOS(有些RTOS的参数信息)。

2.“环形队列”占用资源更小,更适合于资源较小的系统中。

3.“消息队列”结合RTOS应用更加灵活,比如延时、中断传输数据等。

... 最后,这两种队列应用都比较广,建议抽空都研究一下。





审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 嵌入式
    +关注

    关注

    5062

    文章

    18984

    浏览量

    302385
  • RTOS
    +关注

    关注

    21

    文章

    809

    浏览量

    119374
  • FIFO存储
    +关注

    关注

    0

    文章

    103

    浏览量

    5956
  • UART接口
    +关注

    关注

    0

    文章

    124

    浏览量

    15257
  • 裸机
    +关注

    关注

    0

    文章

    39

    浏览量

    6334

原文标题:裸机中环形队列与RTOS中消息队列

文章出处:【微信号:最后一个bug,微信公众号:最后一个bug】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    基于STM32的串口环形队列IAP调试

    基于STM32的串口环形队列IAP调试心得
    的头像 发表于 09-18 15:33 1392次阅读
    基于STM32的串口<b class='flag-5'>环形</b><b class='flag-5'>队列</b>IAP调试

    环形队列在串口数据接收的使用

    前言  书接上回,前文主要介绍了环形队列的实现原理以及C语言实现及测试过程,本文将回归到嵌入式平台的应用,话不多说,淦,上干货!实验目的HAL库下串口的配置及使用环形
    发表于 12-06 06:27

    FreeRtos消息队列API的调用该怎样去实现

    消息队列是什么?消息队列有作用?FreeRtos消息队列API的调用该怎样去实现
    发表于 01-20 07:04

    FreeRTOS消息队列有作用

    。多任务访问  队列不是属于某个特别指定的任务的,任何任务都可以向队列中发送消息,或者从队列中提取消息。原始值传递  队列的消息内容不是引
    发表于 01-27 06:53

    实现队列环形缓冲的方法

    串口队列环形缓冲区队列串口环形缓冲的好处代码实现队列  要实现队列
    发表于 02-21 07:11

    环形队列的相关资料分享

    前言  当代码,不再是简单的完成需求,对代码进行堆砌,而是开始思考如何写出优美代码的时候,我们的代码水平必然会不断提升,今天,咱们来学习环形队列结构。环形队列的基本概念  相信对数据结
    发表于 02-23 06:10

    如何去实现一种队列程序的设计

    队列的原理是什么?队列有作用?如何去实现一种队列程序的设计
    发表于 02-25 07:50

    环形队列的操作如何去实现

    环形队列结构的定义是什么?环形队列的操作如何去实现
    发表于 02-25 06:35

    深度解析数据结构与算法篇之队列环形队列的实现

    01 — 队列简介 队列是种先进先出的数据结构,有个元素进入队列称为入对(enqueue),删除元素称为出队(dequeue),队列有对头(head)和对尾(tail),当有元素进入
    的头像 发表于 06-18 10:07 1885次阅读

    TencentOS-tiny中环形队列的实现

    ; 队尾指针(可变):永远指向此队列的最后一个数据元素; 队列的数据存储方式有两种: ① 基于静态连续内存(数组)存储,如图:② 基于动态内存(链表节点)存储,如图: ❝ 后续都使用基于静态内存存储的
    的头像 发表于 10-08 16:30 1357次阅读

    嵌入式环形队列和消息队列的实现

    嵌入式环形队列和消息队列是实现数据缓存和通信的常见数据结构,广泛应用于嵌入式系统的通信协议和领域。
    的头像 发表于 04-14 11:52 1490次阅读

    嵌入式环形队列和消息队列是如何去实现的?

    嵌入式环形队列和消息队列是实现数据缓存和通信的常见数据结构,广泛应用于嵌入式系统的通信协议和领域。
    发表于 05-20 14:55 1090次阅读

    RTOS消息队列的应用

    基于RTOS的应用,通常使用队列机制实现任务间的数据交互,一个应用程序可以有任意数量的消息队列,每个消息队列都有自己的用途。
    发表于 05-29 10:49 603次阅读
    <b class='flag-5'>RTOS</b>消息<b class='flag-5'>队列</b>的应用

    单片机裸机实现队列功能的方案

    单片机裸机实现队列功能的方案
    的头像 发表于 10-17 14:34 528次阅读

    嵌入式环形队列与消息队列的实现原理

    嵌入式环形队列,也称为环形缓冲区或循环队列,是一种先进先出(FIFO)的数据结构,用于在固定大小的存储区域中高效地存储和访问数据。其主要特点包括固定大小的数组和两个指针(头指针和尾指针
    的头像 发表于 09-02 15:29 296次阅读