網(wǎng)站首頁 編程語言 正文
1.隊列的原理
隊列原理其實就像一個管道,如果我們不斷往管道里面塞乒乓球,每個乒乓球在管道里就會排列一條隊形。先進去的乒乓球就會先出來,這個就是隊列的先進先出的規(guī)則。
球從左邊進去,進去的動作就是入列,然后進去的球在管道里排成一個隊列,這個叫隊列緩存,說白了就是數(shù)組,那么這里存了5個球就相當(dāng)于是buff[5];這樣的意思,最右邊出來的1號球就是最早進去的球,出來的這個動作叫出列,所以遵循了先進先出的規(guī)則。
2.隊列的作用
隊列最主要的作用就是用來緩存數(shù)據(jù),比方說串口接收數(shù)據(jù),我們一般定義一個數(shù)組來存儲數(shù)據(jù),但是假如串口數(shù)據(jù)頻率很快,可能這個數(shù)組里存儲的數(shù)據(jù)還沒處理完,下一組串口數(shù)據(jù)又過來了,那么這時候數(shù)組里的數(shù)據(jù)就會被新數(shù)據(jù)覆蓋,導(dǎo)致老的數(shù)據(jù)丟失。像這種就可以通過隊列的方式來處理,每收到一個字節(jié)數(shù)據(jù)都先入列,然后應(yīng)用程序同步解析處理,根據(jù)隊列先進先出的規(guī)則,那么老的數(shù)據(jù)就不會被新的數(shù)據(jù)“插隊”了。
基于這種緩存數(shù)據(jù)的技術(shù),可以靈活應(yīng)用在各種場景,比如說:
- 1、操作系統(tǒng)的消息傳遞
- 2、大數(shù)據(jù)處理
3.隊列程序設(shè)計思路
其實實現(xiàn)隊列的方法有很多種,但是工作原理都是一樣的,我們要編寫代碼,首先要很清楚隊列的工作原理。
- 1、隊列緩存
- 2、入列
- 3、出列
- 一個隊列基本上要有上面這三個必要的操作,那么隊列緩存就很好理解,說白了就是直接定義一個數(shù)組,數(shù)組大小就是隊列緩存的大小。入列就是把1個或者若干個數(shù)據(jù)按順序存到隊列緩存數(shù)組里,同樣出列把數(shù)據(jù)從隊列緩存里取出來。
入列和出列的原理懂了,那么應(yīng)該怎么樣用程序來實現(xiàn)呢?
4.入列
根據(jù)上文的說法,入列就是把數(shù)據(jù)存進數(shù)組的操作,我們平時存數(shù)組一般都是buff[0]=1;這樣操作。不過在隊列中我們要考慮隊列里當(dāng)前存在多少個數(shù)據(jù)的情況,如果有數(shù)據(jù),那么我們就不能從[0]這個下標(biāo)開始入列,所以我們在入列時要考慮兩個問題:
- 1、隊列緩存可以存儲的數(shù)組下標(biāo)位置,這個我們一般稱為隊尾。
- 2、隊列是否已滿,如果隊列緩存滿了又有新的數(shù)據(jù)入列,該怎么處理?這里我們一般處理方式是按照時間順序,把最早入列的數(shù)據(jù)
丟棄,以新的數(shù)據(jù)替換。
第二個問題先暫時不管,先看第一個問題。根據(jù)前面學(xué)過的數(shù)組與指針,通過指針的特性,我們在用1個指針來代表隊尾,然后這個隊尾指針指向隊列緩存數(shù)組的首地址,當(dāng)入列1個數(shù)據(jù)時,我們的隊尾指針就+1,這樣是不是就能夠知道當(dāng)前隊列緩存的可以存儲的地址了?
5.出列
數(shù)據(jù)入列以后自然要取出來,那么我們?nèi)〉臅r候也是有原則的,不能亂取,而是從最早入列那個數(shù)據(jù)的地址開始取,所以這個出列的數(shù)組下標(biāo)我們稱為隊頭,同樣我們可以使用指針變量來代表這個隊頭。
我們看看下面這個圖是一個出列的流程,我們這個是滿編隊的隊列,總共有1,2,3,4,5個數(shù)據(jù),那么隊頭指針指向隊列緩存首地址,接著第一個出列的就是數(shù)據(jù)1,出列后隊頭指針加1,就指向數(shù)據(jù)2的地址,那么數(shù)據(jù)2出列后,隊頭指針又加1,指向數(shù)據(jù)3的地址,以此類推,這樣就可以實現(xiàn)先進先出的原則。
6.掌握隊列程序編寫
那么我們知道原理后就可以用程序來實現(xiàn)它了,因為一個產(chǎn)品中,會有很多隊列代表不同的數(shù)據(jù),比如說消息我有一個隊列,底層串口接收我也有一個隊列,所以我們吧隊列的一些操作,比如說入列,出列的操作單獨寫成函數(shù)接口,方便程序不同區(qū)域的調(diào)用。
#include#include "Queue.h" Queue4 KeyMsg; int main(int argc, char *argv[]) { ?? ?unsigned char a;? ?? ?QueueEmpty(KeyMsg);/*初始化*/ ?? ?printf("site:%d\r\n",sizeof(KeyMsg.Buff));? ?? ?printf("&KeyMsg=0x%x, KeyMsg.Buff=0x%x, KeyMsg.Head=0x%x, KeyMsg.Tail=0x%x\r\n",&KeyMsg,KeyMsg.Buff,KeyMsg.Head,KeyMsg.Tail); ?? ?printf("&buff[0]=0x%x, &buff[1]=0x%x, &buff[2]=0x%x, &buff[3]=0x%x \r\n",&KeyMsg.Buff[0],&KeyMsg.Buff[1],&KeyMsg.Buff[2],&KeyMsg.Buff[3]); ?? ?printf("\r\n");? ?? ? ?? ?a = 1; ?? ?QueueDataIn(KeyMsg,&a,1);/*要用哪一個隊列,要存那個數(shù)據(jù),要存多少個數(shù)據(jù)*/ ?? ?printf("&KeyMsg=0x%x, KeyMsg.Buff=0x%x, KeyMsg.Head=0x%x, KeyMsg.Tail=0x%x\r\n",&KeyMsg,KeyMsg.Buff,KeyMsg.Head,KeyMsg.Tail); ?? ?printf("buff[0]=0x%x, buff[1]=0x%x, buff[2]=0x%x, buff[3]=0x%x \r\n",KeyMsg.Buff[0],KeyMsg.Buff[1],KeyMsg.Buff[2],KeyMsg.Buff[3]); ?? ?printf("\r\n");? ?? ? ?? ?a = 2; ?? ?QueueDataIn(KeyMsg,&a,1); ?? ?printf("&KeyMsg=0x%x, KeyMsg.Buff=0x%x, KeyMsg.Head=0x%x, KeyMsg.Tail=0x%x\r\n",&KeyMsg,KeyMsg.Buff,KeyMsg.Head,KeyMsg.Tail); ?? ?printf("buff[0]=0x%x, buff[1]=0x%x, buff[2]=0x%x, buff[3]=0x%x \r\n",KeyMsg.Buff[0],KeyMsg.Buff[1],KeyMsg.Buff[2],KeyMsg.Buff[3]); ?? ?printf("\r\n");? ?? ? ?? ?a = 3; ?? ?QueueDataIn(KeyMsg,&a,1); ?? ?printf("&KeyMsg=0x%x, KeyMsg.Buff=0x%x, KeyMsg.Head=0x%x, KeyMsg.Tail=0x%x\r\n",&KeyMsg,KeyMsg.Buff,KeyMsg.Head,KeyMsg.Tail); ?? ?printf("buff[0]=0x%x, buff[1]=0x%x, buff[2]=0x%x, buff[3]=0x%x \r\n",KeyMsg.Buff[0],KeyMsg.Buff[1],KeyMsg.Buff[2],KeyMsg.Buff[3]); ?? ?printf("\r\n");? ?? ? ? ? a = 4; ?? ?QueueDataIn(KeyMsg,&a,1); ?? ?printf("&KeyMsg=0x%x, KeyMsg.Buff=0x%x, KeyMsg.Head=0x%x, KeyMsg.Tail=0x%x\r\n",&KeyMsg,KeyMsg.Buff,KeyMsg.Head,KeyMsg.Tail); ?? ?printf("buff[0]=0x%x, buff[1]=0x%x, buff[2]=0x%x, buff[3]=0x%x \r\n",KeyMsg.Buff[0],KeyMsg.Buff[1],KeyMsg.Buff[2],KeyMsg.Buff[3]); ?? ?printf("\r\n");? ?? ? ?? ?a = 5; ?? ?QueueDataIn(KeyMsg,&a,1); ?? ?printf("&KeyMsg=0x%x, KeyMsg.Buff=0x%x, KeyMsg.Head=0x%x, KeyMsg.Tail=0x%x\r\n",&KeyMsg,KeyMsg.Buff,KeyMsg.Head,KeyMsg.Tail); ?? ?printf("buff[0]=0x%x, buff[1]=0x%x, buff[2]=0x%x, buff[3]=0x%x \r\n",KeyMsg.Buff[0],KeyMsg.Buff[1],KeyMsg.Buff[2],KeyMsg.Buff[3]); ?? ?printf("\r\n");? ?? ? ?? ?printf("&KeyMsg=0x%x, KeyMsg.Buff=0x%x, KeyMsg.Head=0x%x, KeyMsg.Tail=0x%x\r\n",&KeyMsg,KeyMsg.Buff,KeyMsg.Head,KeyMsg.Tail); ?? ?QueueDataOut(KeyMsg,&a);/*要用哪一個隊列,要取那個數(shù)據(jù)*/ ?? ?printf("a=%d\r\n",a);? ?? ?printf("&KeyMsg=0x%x, KeyMsg.Buff=0x%x, KeyMsg.Head=0x%x, KeyMsg.Tail=0x%x\r\n",&KeyMsg,KeyMsg.Buff,KeyMsg.Head,KeyMsg.Tail); ?? ?printf("buff[0]=0x%x, buff[1]=0x%x, buff[2]=0x%x, buff[3]=0x%x \r\n",KeyMsg.Buff[0],KeyMsg.Buff[1],KeyMsg.Buff[2],KeyMsg.Buff[3]); ?? ?printf("\r\n");? ?? ? ?? ?return 0; }
queue.c代碼
void S_QueueEmpty(unsigned char **Head,unsigned char **Tail,unsigned char *pBuff) { ?? ?*Head = pBuff; ?? ?*Tail = pBuff;? } void S_QueueDataIn(unsigned char **Head,unsigned char **Tail,unsigned char *pBuff,unsigned char Len,unsigned char *pData,unsigned char DataLen) { ?? ?unsigned char num; ?? ?//關(guān)閉中斷? ?? ?for(num=0; num < DataLen; num++,pData++) ?? ?{?? ? ?? ??? ?**Tail = *pData;?? ??? ?//這里把數(shù)據(jù)入列? ?? ??? ?(*Tail)++;?? ??? ??? ??? ?//隊尾指針加1 ?? ? ?? ?if(*Tail == pBuff+Len) ?? ? ?? ?{ ?? ? ?? ??? ?*Tail = pBuff;? ?? ? ?? ?} ?? ??? ?if(*Tail == *Head) ?? ??? ?{ ?? ??? ??? ? ?? ??? ??? ?if(++(*Head) == pBuff+Len) ?? ??? ??? ?{ ?? ??? ??? ??? ?*Head = pBuff;?? ? ?? ??? ??? ?} ?? ??? ?} ?? ?} ?? ?//打開中斷? } unsigned char S_QueueDataOut(unsigned char **Head,unsigned char **Tail,unsigned char *pBuff,unsigned char Len,unsigned char *pData) { ?? ?unsigned char status; ?? ?//關(guān)閉中斷? ?? ?status = 0; ?? ?if(*Head != *Tail) ?? ?{ ?? ??? ?*pData = **Head; ?? ??? ?status = 1; ?? ??? ?if(++(*Head) == pBuff+Len) ?? ??? ?{ ?? ??? ??? ?*Head = pBuff; ?? ??? ?} ?? ?} ?? ?//恢復(fù)中斷? ?? ?return status; } unsigned short S_QueueDataLen(unsigned char **Head,unsigned char **Tail,unsigned char *pBuff,unsigned char Len) { ?? ?if(*Tail > *Head) ?? ?{ ?? ??? ?return *Tail-*Head; ?? ?} ?? ?if(*Tail < *Head) ?? ?{ ?? ??? ?return *Tail+Len-*Head;?? ? ?? ?} }
queue.h代碼
#ifndef _QUEUE_H_ #define _QUEUE_H_ extern void S_QueueEmpty(unsigned char **Head,unsigned char **Tail,unsigned char *pBuff); extern void S_QueueDataIn(unsigned char **Head,unsigned char **Tail,unsigned char *pBuff,unsigned char Len,unsigned char *pData,unsigned char DataLen); extern unsigned char S_QueueDataOut(unsigned char **Head,unsigned char **Tail,unsigned char *pBuff,unsigned char Len,unsigned char *pData);? extern unsigned short S_QueueDataLen(unsigned char **Head,unsigned char **Tail,unsigned char *pBuff,unsigned char Len);? #define QueueEmpty(x) ?S_QueueEmpty((unsigned char **)&(x).Head,(unsigned char **)&(x).Tail,(unsigned char *)(x).Buff) #define QueueDataIn(x,y,z) S_QueueDataIn((unsigned char **)&(x).Head,(unsigned char **)&(x).Tail,(unsigned char *)&(x).Buff,sizeof((x).Buff),y,z) #define QueueDataOut(x,y) ?S_QueueDataOut((unsigned char **)&(x).Head,(unsigned char **)&(x).Tail,(unsigned char *)&(x).Buff,sizeof((x).Buff),y) #define QueueDataLen(x) ?? ?S_QueueDataLen((unsigned char **)&(x).Head,(unsigned char **)&(x).Tail,(unsigned char *)&(x).Buff,sizeof((x).Buff)) ? typedef struct { ?? ?unsigned char *Head; ?? ?//隊頭指針,用來出列用的? ?? ?unsigned char *Tail; ?? ?//隊尾指針,用來入列用的? ?? ?unsigned char Buff[4];?? ?//隊列緩存? }Queue4; typedef struct { ?? ?unsigned char *Head; ?? ?//隊頭指針,用來出列用的? ?? ?unsigned char *Tail; ?? ?//隊尾指針,用來入列用的? ?? ?unsigned char Buff[128];?? ?//隊列緩存? }Queue128; typedef struct { ?? ?unsigned char *Head; ?? ?//隊頭指針,用來出列用的? ?? ?unsigned char *Tail; ?? ?//隊尾指針,用來入列用的? ?? ?unsigned char Buff[512];?? ?//隊列緩存? }Queue512; #endif
7.隊列的應(yīng)用
串口的應(yīng)用:
如果產(chǎn)品有兩個功能,一個功能需要燈一秒閃1次,另一個功能需要燈1秒閃2次,在功能切換很快的情況下,需要功能正常并且燈的閃爍正常,那么就需要隊列了。
原文鏈接:https://blog.csdn.net/weixin_44795447/article/details/123201835
相關(guān)推薦
- 2022-04-07 C#實現(xiàn)Socket服務(wù)器及多客戶端連接的方式_C#教程
- 2022-10-29 在Centos8中安裝配置Redis,實現(xiàn)遠程訪問
- 2022-11-24 C++?OpenCV實現(xiàn)boxfilter方框濾波的方法詳解_C 語言
- 2022-06-06 ASP.NET的Core?AD域登錄過程示例_ASP.NET
- 2022-06-17 go語言beego框架web開發(fā)語法筆記示例_Golang
- 2022-05-12 寶塔面板配置SSL證書
- 2022-09-18 詳解React?hooks組件通信方法_React
- 2022-09-03 Python標(biāo)準(zhǔn)庫sys庫常用功能詳解_python
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支