C語言隊列和應用詳情

1.隊列的原理

隊列原理其實就像一個管道,如果我們不斷往管道裡面塞乒乓球,每個乒乓球在管道裡就會排列一條隊形。先進去的乒乓球就會先出來,這個就是隊列的先進先出的規則。

球從左邊進去,進去的動作就是入列,然後進去的球在管道裡排成一個隊列,這個叫隊列緩存,說白瞭就是數組,那麼這裡存瞭5個球就相當於是buff[5];這樣的意思,最右邊出來的1號球就是最早進去的球,出來的這個動作叫出列,所以遵循瞭先進先出的規則。

2.隊列的作用

隊列最主要的作用就是用來緩存數據,比方說串口接收數據,我們一般定義一個數組來存儲數據,但是假如串口數據頻率很快,可能這個數組裡存儲的數據還沒處理完,下一組串口數據又過來瞭,那麼這時候數組裡的數據就會被新數據覆蓋,導致老的數據丟失。像這種就可以通過隊列的方式來處理,每收到一個字節數據都先入列,然後應用程序同步解析處理,根據隊列先進先出的規則,那麼老的數據就不會被新的數據“插隊”瞭。

基於這種緩存數據的技術,可以靈活應用在各種場景,比如說:

  • 1、操作系統的消息傳遞
  • 2、大數據處理

3.隊列程序設計思路

其實實現隊列的方法有很多種,但是工作原理都是一樣的,我們要編寫代碼,首先要很清楚隊列的工作原理。

  • 1、隊列緩存
  • 2、入列
  • 3、出列
  • 一個隊列基本上要有上面這三個必要的操作,那麼隊列緩存就很好理解,說白瞭就是直接定義一個數組,數組大小就是隊列緩存的大小。入列就是把1個或者若幹個數據按順序存到隊列緩存數組裡,同樣出列把數據從隊列緩存裡取出來。

入列和出列的原理懂瞭,那麼應該怎麼樣用程序來實現呢?

4.入列

根據上文的說法,入列就是把數據存進數組的操作,我們平時存數組一般都是buff[0]=1;這樣操作。不過在隊列中我們要考慮隊列裡當前存在多少個數據的情況,如果有數據,那麼我們就不能從[0]這個下標開始入列,所以我們在入列時要考慮兩個問題:

  • 1、隊列緩存可以存儲的數組下標位置,這個我們一般稱為隊尾。
  • 2、隊列是否已滿,如果隊列緩存滿瞭又有新的數據入列,該怎麼處理?這裡我們一般處理方式是按照時間順序,把最早入列的數據

丟棄,以新的數據替換。
第二個問題先暫時不管,先看第一個問題。根據前面學過的數組與指針,通過指針的特性,我們在用1個指針來代表隊尾,然後這個隊尾指針指向隊列緩存數組的首地址,當入列1個數據時,我們的隊尾指針就+1,這樣是不是就能夠知道當前隊列緩存的可以存儲的地址瞭?

5.出列

數據入列以後自然要取出來,那麼我們取的時候也是有原則的,不能亂取,而是從最早入列那個數據的地址開始取,所以這個出列的數組下標我們稱為隊頭,同樣我們可以使用指針變量來代表這個隊頭。
我們看看下面這個圖是一個出列的流程,我們這個是滿編隊的隊列,總共有1,2,3,4,5個數據,那麼隊頭指針指向隊列緩存首地址,接著第一個出列的就是數據1,出列後隊頭指針加1,就指向數據2的地址,那麼數據2出列後,隊頭指針又加1,指向數據3的地址,以此類推,這樣就可以實現先進先出的原則。

6.掌握隊列程序編寫

那麼我們知道原理後就可以用程序來實現它瞭,因為一個產品中,會有很多隊列代表不同的數據,比如說消息我有一個隊列,底層串口接收我也有一個隊列,所以我們吧隊列的一些操作,比如說入列,出列的操作單獨寫成函數接口,方便程序不同區域的調用。

#include <stdio.h>
#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);/*要用哪一個隊列,要存那個數據,要存多少個數據*/
    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);/*要用哪一個隊列,要取那個數據*/
    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;
    //關閉中斷 
    for(num=0; num < DataLen; num++,pData++)
    {    
        **Tail = *pData;        //這裡把數據入列 
        (*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;
    //關閉中斷 
    status = 0;
    if(*Head != *Tail)
    {
        *pData = **Head;
        status = 1;
        if(++(*Head) == pBuff+Len)
        {
            *Head = pBuff;
        }
    }
    //恢復中斷 
    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.隊列的應用

串口的應用:

如果產品有兩個功能,一個功能需要燈一秒閃1次,另一個功能需要燈1秒閃2次,在功能切換很快的情況下,需要功能正常並且燈的閃爍正常,那麼就需要隊列瞭。

到此這篇關於C語言隊列和應用詳情的文章就介紹到這瞭,更多相關C語言隊列和應用內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: