閱讀366 返回首頁    go 技術社區[雲棲]


Linux下入隊列和出隊列操作的C代碼示例

**概述 **
最近有在校的學生朋友在問我,數據結構中的隊列在實際的軟件開發項目中有什麼樣的用處。

大家都知道,隊列的特點是先入先出,即數據是按照入隊列的順序出隊列的。在實際的軟件開發項目中,當一個中間模塊需要接收和發送大量的消息時,隊列就可以大展身手了。我們可以將接收到的數據存儲在一個全局隊列中,然後在另外的程序流程中將數據從同一個全局隊列中取出來,經過一定的處理之後將消息發送到另外的模塊。這樣做可以降低程序的性能瓶頸。

本文用實際的C代碼示例了簡單的數據入隊列和出隊列的方法,大家可據此了解隊列的實際用法,也可參照來實現更加複雜的隊列操作。

C代碼

/**********************************************************************
* 版權所有 (C)2016, Zhou Zhaoxiong
*
* 文件名稱:QueueUse.c
* 文件標識:無
* 內容摘要:示例隊列的使用(入隊和出隊)
* 其它說明:無
* 當前版本:V1.0
* 作    者:Zhou Zhaoxiong
* 完成日期:20160811
*
**********************************************************************/
#include <stdio.h>
#include <string.h>
#include <ftw.h>
#include <pthread.h>
#include <time.h>


// 重定義數據類型
typedef signed   int        INT32;
typedef unsigned int        UINT32;
typedef unsigned char       UINT8;

// 宏定義
#define     MAX_QUEUE      10000          // 最大隊列元素個數

// 結構體變量
typedef struct
{
    UINT32 iID;             // 編號
    UINT8  szInfo[100];     // 描述
} T_StructInfo;

// 全局變量定義
T_StructInfo g_tQueue[MAX_QUEUE] = {0};      // 隊列結構體
UINT32 g_iQueueHead = 0;                     // 隊列頭部索引
UINT32 g_iQueueTail = 0;                     // 隊列尾部索引
pthread_mutex_t     g_mutex_queue_cs;        // 互斥信號量
pthread_cond_t      queue_cv;
pthread_mutexattr_t g_MutexAttr;

// 函數聲明
void PutDataIntoQueue(void);
void GetDataFromQueue(void);
INT32 EnQueue(T_StructInfo tQueueData);
INT32 DeQueue(T_StructInfo *ptStructData);
void Sleep(UINT32 iCountMs);


/****************************************************************
* 功能描述: 主函數
* 輸入參數: 無
* 輸出參數: 無
* 返 回 值: 0-執行完成
* 其他說明: 無
* 修改日期       版本號        修改人        修改內容
* -------------------------------------------------------------
* 20160811        V1.0     Zhou Zhaoxiong     創建
****************************************************************/
INT32 main(void)
{
    pthread_mutex_init(&g_mutex_queue_cs, &g_MutexAttr);
    pthread_cond_init(&queue_cv, NULL);


    // 在循環中執行入隊和出隊操作
    while (1)
    {
        PutDataIntoQueue();  // 數據入隊


        Sleep(5 * 1000);     // 間隔5秒


        GetDataFromQueue();  // 數據出隊


        Sleep(60 * 1000);    // 每一分鍾執行一次出隊和入隊
    }


    return 0;
}




/****************************************************************
* 功能描述: 將數據加入隊列中
* 輸入參數: 無
* 輸出參數: 無
* 返 回 值: 0-成功   -1-失敗
* 其他說明: 無
* 修改日期       版本號        修改人        修改內容
* -------------------------------------------------------------
* 20160811        V1.0     Zhou Zhaoxiong     創建
****************************************************************/
void PutDataIntoQueue(void)
{
    T_StructInfo tQueueData = {0};
    static UINT32 iCountNum = 0;


    // 對結構體的變量進行賦值
    tQueueData.iID = iCountNum;
    snprintf(tQueueData.szInfo, sizeof(tQueueData.szInfo) - 1, "zhou%d", iCountNum);


    // 計數值累加
    iCountNum ++;
    if (iCountNum >= MAX_QUEUE-1)
    {
        iCountNum = 0;
    }


    // 將數據加入隊列(一直等到加入成功之後才退出)
    while (EnQueue(tQueueData) == -1)
    {
        Sleep(1000);       // 加入失敗,1秒後重試
    }


    // 打印加入的數據
    printf("PutDataIntoQueue: ID=%d, Info=%s\n", tQueueData.iID, tQueueData.szInfo);
}




/****************************************************************
* 功能描述: 將數據取出隊列中
* 輸入參數: 無
* 輸出參數: 無
* 返 回 值: 0-成功   -1-失敗
* 其他說明: 無
* 修改日期       版本號        修改人        修改內容
* -------------------------------------------------------------
* 20160811        V1.0     Zhou Zhaoxiong     創建
****************************************************************/
void GetDataFromQueue(void)
{
    T_StructInfo tQueueData = {0};


    if (DeQueue(&tQueueData) == -1)
    {
        return;
    }


    // 打印取出的數據
    printf("GetDataFromQueue: ID=%d, Info=%s\n", tQueueData.iID, tQueueData.szInfo);
}




/****************************************************************
* 功能描述: 數據入隊列
* 輸入參數: tQueueData-隊列數據
* 輸出參數: 無
* 返 回 值: 0-成功   -1-失敗
* 其他說明: 無
* 修改日期       版本號        修改人        修改內容
* -------------------------------------------------------------
* 20160811        V1.0     Zhou Zhaoxiong     創建
****************************************************************/
INT32 EnQueue(T_StructInfo tQueueData)
{
    INT32  iRetVal  = 0;
    UINT32 iNextPos = 0;


    pthread_mutex_lock(&g_mutex_queue_cs);
    iNextPos = g_iQueueTail + 1;


    if (iNextPos >= MAX_QUEUE)
    {
        iNextPos = 0;
    }


    if (iNextPos == g_iQueueHead)
    {
        iRetVal = -1;   // 已達到隊列的最大長度
    }
    else
    {
        // 入隊列
        memset(&g_tQueue[g_iQueueTail], 0x00,  sizeof(T_StructInfo));
        memcpy(&g_tQueue[g_iQueueTail], &tQueueData, sizeof(T_StructInfo));


        g_iQueueTail = iNextPos;
    }


    pthread_cond_signal(&queue_cv);
    pthread_mutex_unlock(&g_mutex_queue_cs);


    return iRetVal;
}




/****************************************************************
* 功能描述: 數據出隊列
* 輸入參數: ptStructData-隊列數據
* 輸出參數: 無
* 返 回 值: 0-成功   -1-失敗
* 其他說明: 無
* 修改日期       版本號        修改人        修改內容
* -------------------------------------------------------------
* 20160811        V1.0     Zhou Zhaoxiong     創建
****************************************************************/
INT32 DeQueue(T_StructInfo *ptStructData)
{
    T_StructInfo tQueueData = {0};


    if (ptStructData == NULL)
    {
        return -1;
    }


    pthread_mutex_lock(&g_mutex_queue_cs);


    while (g_iQueueHead == g_iQueueTail)
    {
        pthread_cond_wait(&queue_cv, &g_mutex_queue_cs);
    }


    memset(&tQueueData, 0x00, sizeof(T_StructInfo));
    memcpy(&tQueueData, &g_tQueue[g_iQueueHead], sizeof(T_StructInfo));
    g_iQueueHead ++;


    if (g_iQueueHead >= MAX_QUEUE)
    {
        g_iQueueHead = 0;
    }


    pthread_mutex_unlock(&g_mutex_queue_cs);
    memcpy(ptStructData, &tQueueData, sizeof(T_StructInfo));


    return 0;
}




/**********************************************************************
* 功能描述: 程序休眠
* 輸入參數: iCountMs-休眠時間(單位:ms)
* 輸出參數: 無
* 返 回 值: 無
* 其它說明: 無
* 修改日期      版本號       修改人        修改內容
* ------------------------------------------------------------------
* 20160811       V1.0     Zhou Zhaoxiong     創建
********************************************************************/ 
void Sleep(UINT32 iCountMs)
{
    struct timeval t_timeout = {0};


    if (iCountMs < 1000)
    {
        t_timeout.tv_sec  = 0;
        t_timeout.tv_usec = iCountMs * 1000;
    }
    else
    {
        t_timeout.tv_sec  = iCountMs / 1000;
        t_timeout.tv_usec = (iCountMs % 1000) * 1000;
    }
    select(0, NULL, NULL, NULL, &t_timeout);    // 調用select函數阻塞程序
}

程序運行情況
我們將上麵編寫好的QueueUse.c文件上傳到Linux機器上,使用“gcc -g -o QueueUseQueueUse.c”命令編譯之後,生成QueueUse文件。之後,執行“QueueUse”命令,即可看到程序的運行結果(結果會不斷地更新)如下:

~/zhouzx/Test/QueueUse> QueueUse
PutDataIntoQueue: ID=0, Info=zhou0
GetDataFromQueue: ID=0, Info=zhou0
PutDataIntoQueue: ID=1, Info=zhou1
GetDataFromQueue: ID=1, Info=zhou1
PutDataIntoQueue: ID=2, Info=zhou2
GetDataFromQueue: ID=2, Info=zhou2
PutDataIntoQueue: ID=3, Info=zhou3
GetDataFromQueue: ID=3, Info=zhou3

我們看到,數據先是被加入到隊列中,然後再從隊列中取出來。

程序說明
第一,在本程序中,入隊列和出隊列是在同一個函數中完成的,但是,在實際開發項目的程序中,入隊列和出隊列一般是在不同的程序流程(兩個不同的線程)中完成的。

第二,本程序的數據入隊列操作是在EnQueue函數中完成的,數據出隊列操作是在DeQueue函數中完成的,全局變量g_tQueue用於存放需要處理的數據。

第三,在實際開發項目的程序中,有可能會有很多流程都會調用入隊列和出隊列的函數,為了防止多個流程同時向隊列中加入數據或取出數據,在EnQueue和DeQueue函數中使用了鎖操作。也就是說,在操作數據之前,先用pthread_mutex_lock函數執行加鎖操作,在處理完數據之後,再用pthread_mutex_unlock函數執行解鎖操作。

第四,在實際開發項目中,為了防止程序從隊列中取數據的速率過快而使得下遊模塊處理不過來,我們常在從隊列取出數據之後發消息的流程中控製數據的發送速率,具體每秒鍾發送多少條可在配置文件中設置。

最後更新:2017-10-12 21:33:10

  上一篇:go 
  下一篇:go 嫌犯現身路口 “雲眼”立刻彈窗警告 雲棲大會展示人臉識別技術