TencentOS-tiny中队列、环形队列、优先级队列的实现及使用
扫描二维码
随时随地手机看文章
ce编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 25px;">1. 什么是队列
队列(queue)是一种只能在一端插入元素、在另一端删除元素的数据结构,遵循「先入先出」(FIFO)的规则。队列中有两个基本概念:- 队头指针(可变):永远指向此队列的第一个数据元素;
- 队尾指针(可变):永远指向此队列的最后一个数据元素;
❝后续都使用基于静态内存存储的队列讲解。❞队列提供两个统一的操作:
- 「入队(enqueue)」
- 「出队(dequeue)」
2. 环形队列
2.1. 环形队列的特点
普通队列的入队操作将队尾指针后移 1,出队操作将队头指针后移 1,操作几次之后会发现队头指针和队尾指针都跑到缓冲区的尾部去了:这就导致了前面的内存空间全被浪费,如果要重新恢复使用,则需要进行元素和指针的移动:显然这种队列使用方式太不方便了,所以就诞生了环形队列:「不用搬移元素和指针,一直可以重复利用这段内存空间」。2.2. 环形队列的实现
TencentOS-tiny中环形队列的实现在tos_ring_queue.h
和tos_ring_queue.c
中。typedef struct k_ring_queue_st {
knl_obj_t knl_obj;
uint16_t head; //队头指针
uint16_t tail; //队尾指针
size_t total; //记录队列中元素的个数
uint8_t *pool; //队列底层的存储结构(一个数组)
size_t item_size; //队列中每个元素的大小,单位:字节
size_t item_cnt; //队列中可以容纳的元素数量
} k_ring_q_t;
环形队列初始化,将队头指针和队尾置0: __API__ k_err_t tos_ring_q_create(k_ring_q_t *ring_q, void *pool, size_t item_cnt, size_t item_size)
{
//省略了参数合法性检查代码
ring_q->head = 0u;
ring_q->tail = 0u;
ring_q->total = 0;
ring_q->pool = (uint8_t *)pool;
ring_q->item_size = item_size;
ring_q->item_cnt = item_cnt;
return K_ERR_NONE;
}
判断环形队列是否为满或者为空:__API__ int tos_ring_q_is_empty(k_ring_q_t *ring_q)
{
TOS_CPU_CPSR_ALLOC();
int is_empty = K_FALSE;
//省略了参数合法性检查代码
TOS_CPU_INT_DISABLE();
is_empty = (ring_q->total == 0 ? K_TRUE : K_FALSE);
TOS_CPU_INT_ENABLE();
return is_empty;
}
__API__ int tos_ring_q_is_full(k_ring_q_t *ring_q)
{
TOS_CPU_CPSR_ALLOC();
int is_full = K_FALSE;
//省略了参数合法性检查代码
TOS_CPU_INT_DISABLE();
is_full = (ring_q->total == ring_q->item_cnt ? K_TRUE : K_FALSE);
TOS_CPU_INT_ENABLE();
return is_full;
}
环形队列入队操作的API如下:__API__ k_err_t tos_ring_q_enqueue(k_ring_q_t *ring_q, void *item, size_t item_size);
在此API中,入队操作的实现如下:__STATIC_INLINE__ void ring_q_item_increase(k_ring_q_t *ring_q)
{
ring_q->tail = RING_NEXT(ring_q, ring_q->tail);
ring_q->total;
}
环形队列出队操作的API如下:__API__ k_err_t tos_ring_q_dequeue(k_ring_q_t *ring_q, void *item, size_t *item_size);
在此API中,出队操作的实现如下:__STATIC_INLINE__ void ring_q_item_decrease(k_ring_q_t *ring_q)
{
ring_q->head = RING_NEXT(ring_q, ring_q->head);
--ring_q->total;
}
在入队和出队操作的时候都使用了 RING_NEXT 宏,用来获取在环形队列中的下一个位置:#define RING_NEXT(ring_q, index) ((index 1) % ring_q->item_cnt)
2.3. 环形队列使用Demo
编写如下的测试代码:ce;font-size: 12px;-webkit-overflow-scrolling: touch;letter-spacing: 0px;padding-top: 15px;background: #f8f8f8;border-radius: 5px;">#include
typedef struct item_st {
int a;
int b;
int c;
} item_t;
#define RING_QUEUE_ITEM_MAX 5
uint8_t ring_q_buffer[RING_QUEUE_ITEM_MAX * sizeof(item_t)];
k_ring_q_t ring_q;
void entry_task_demo(void *arg)
{
k_err_t err;
int i;
item_t item;
size_t item_size;
//创建环形队列
tos_ring_q_create(