軟件開發(fā)實(shí)踐中的入隊(duì)列和出隊(duì)列操作的C代碼示例
概述
最近有在校的學(xué)生朋友在問我,數(shù)據(jù)結(jié)構(gòu)中的隊(duì)列在實(shí)際的軟件開發(fā)項(xiàng)目中有什么樣的用處。
大家都知道,隊(duì)列的特點(diǎn)是先入先出,即數(shù)據(jù)是按照入隊(duì)列的順序出隊(duì)列的。在實(shí)際的軟件開發(fā)項(xiàng)目中,當(dāng)一個(gè)中間模塊需要接收和發(fā)送大量的消息時(shí),隊(duì)列就可以大展身手了。我們可以將接收到的數(shù)據(jù)存儲(chǔ)在一個(gè)全局隊(duì)列中,然后在另外的程序流程中將數(shù)據(jù)從同一個(gè)全局隊(duì)列中取出來,經(jīng)過一定的處理之后將消息發(fā)送到另外的模塊。這樣做可以降低程序的性能瓶頸。
本文用實(shí)際的C代碼示例了簡(jiǎn)單的數(shù)據(jù)入隊(duì)列和出隊(duì)列的方法,大家可據(jù)此了解隊(duì)列的實(shí)際用法,也可參照來實(shí)現(xiàn)更加復(fù)雜的隊(duì)列操作。
C代碼
- /**********************************************************************
- * 版權(quán)所有 (C)2016, Zhou Zhaoxiong
- *
- * 文件名稱:QueueUse.c
- * 文件標(biāo)識(shí):無
- * 內(nèi)容摘要:示例隊(duì)列的使用(入隊(duì)和出隊(duì))
- * 其它說明:無
- * 當(dāng)前版本:V1.0
- * 作 者:Zhou Zhaoxiong
- * 完成日期:20160811
- *
- **********************************************************************/
- #include <stdio.h>
- #include <string.h>
- #include <ftw.h>
- #include <pthread.h>
- #include <time.h>
- // 重定義數(shù)據(jù)類型
- typedef signed int INT32;
- typedef unsigned int UINT32;
- typedef unsigned char UINT8;
- // 宏定義
- #define MAX_QUEUE 10000 // ***隊(duì)列元素個(gè)數(shù)
- // 結(jié)構(gòu)體變量
- typedef struct
- {
- UINT32 iID; // 編號(hào)
- UINT8 szInfo[100]; // 描述
- } T_StructInfo;
- // 全局變量定義
- T_StructInfo g_tQueue[MAX_QUEUE] = {0}; // 隊(duì)列結(jié)構(gòu)體
- UINT32 g_iQueueHead = 0; // 隊(duì)列頭部索引
- UINT32 g_iQueueTail = 0; // 隊(duì)列尾部索引
- pthread_mutex_t g_mutex_queue_cs; // 互斥信號(hào)量
- pthread_cond_t queue_cv;
- pthread_mutexattr_t g_MutexAttr;
- // 函數(shù)聲明
- void PutDataIntoQueue(void);
- void GetDataFromQueue(void);
- INT32 EnQueue(T_StructInfo tQueueData);
- INT32 DeQueue(T_StructInfo *ptStructData);
- void Sleep(UINT32 iCountMs);
- /****************************************************************
- * 功能描述: 主函數(shù)
- * 輸入?yún)?shù): 無
- * 輸出參數(shù): 無
- * 返 回 值: 0-執(zhí)行完成
- * 其他說明: 無
- * 修改日期 版本號(hào) 修改人 修改內(nèi)容
- * -------------------------------------------------------------
- * 20160811 V1.0 Zhou Zhaoxiong 創(chuàng)建
- ****************************************************************/
- INT32 main(void)
- {
- pthread_mutex_init(&g_mutex_queue_cs, &g_MutexAttr);
- pthread_cond_init(&queue_cv, NULL);
- // 在循環(huán)中執(zhí)行入隊(duì)和出隊(duì)操作
- while (1)
- {
- PutDataIntoQueue(); // 數(shù)據(jù)入隊(duì)
- Sleep(5 * 1000); // 間隔5秒
- GetDataFromQueue(); // 數(shù)據(jù)出隊(duì)
- Sleep(60 * 1000); // 每一分鐘執(zhí)行一次出隊(duì)和入隊(duì)
- }
- return 0;
- }
- /****************************************************************
- * 功能描述: 將數(shù)據(jù)加入隊(duì)列中
- * 輸入?yún)?shù): 無
- * 輸出參數(shù): 無
- * 返 回 值: 0-成功 -1-失敗
- * 其他說明: 無
- * 修改日期 版本號(hào) 修改人 修改內(nèi)容
- * -------------------------------------------------------------
- * 20160811 V1.0 Zhou Zhaoxiong 創(chuàng)建
- ****************************************************************/
- void PutDataIntoQueue(void)
- {
- T_StructInfo tQueueData = {0};
- static UINT32 iCountNum = 0;
- // 對(duì)結(jié)構(gòu)體的變量進(jìn)行賦值
- tQueueData.iID = iCountNum;
- snprintf(tQueueData.szInfo, sizeof(tQueueData.szInfo) - 1, "zhou%d", iCountNum);
- // 計(jì)數(shù)值累加
- iCountNum ++;
- if (iCountNum >= MAX_QUEUE-1)
- {
- iCountNum = 0;
- }
- // 將數(shù)據(jù)加入隊(duì)列(一直等到加入成功之后才退出)
- while (EnQueue(tQueueData) == -1)
- {
- Sleep(1000); // 加入失敗,1秒后重試
- }
- // 打印加入的數(shù)據(jù)
- printf("PutDataIntoQueue: ID=%d, Info=%s\n", tQueueData.iID, tQueueData.szInfo);
- }
- /****************************************************************
- * 功能描述: 將數(shù)據(jù)取出隊(duì)列中
- * 輸入?yún)?shù): 無
- * 輸出參數(shù): 無
- * 返 回 值: 0-成功 -1-失敗
- * 其他說明: 無
- * 修改日期 版本號(hào) 修改人 修改內(nèi)容
- * -------------------------------------------------------------
- * 20160811 V1.0 Zhou Zhaoxiong 創(chuàng)建
- ****************************************************************/
- void GetDataFromQueue(void)
- {
- T_StructInfo tQueueData = {0};
- if (DeQueue(&tQueueData) == -1)
- {
- return;
- }
- // 打印取出的數(shù)據(jù)
- printf("GetDataFromQueue: ID=%d, Info=%s\n", tQueueData.iID, tQueueData.szInfo);
- }
- /****************************************************************
- * 功能描述: 數(shù)據(jù)入隊(duì)列
- * 輸入?yún)?shù): tQueueData-隊(duì)列數(shù)據(jù)
- * 輸出參數(shù): 無
- * 返 回 值: 0-成功 -1-失敗
- * 其他說明: 無
- * 修改日期 版本號(hào) 修改人 修改內(nèi)容
- * -------------------------------------------------------------
- * 20160811 V1.0 Zhou Zhaoxiong 創(chuàng)建
- ****************************************************************/
- 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; // 已達(dá)到隊(duì)列的***長(zhǎng)度
- }
- else
- {
- // 入隊(duì)列
- 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;
- }
- /****************************************************************
- * 功能描述: 數(shù)據(jù)出隊(duì)列
- * 輸入?yún)?shù): ptStructData-隊(duì)列數(shù)據(jù)
- * 輸出參數(shù): 無
- * 返 回 值: 0-成功 -1-失敗
- * 其他說明: 無
- * 修改日期 版本號(hào) 修改人 修改內(nèi)容
- * -------------------------------------------------------------
- * 20160811 V1.0 Zhou Zhaoxiong 創(chuàng)建
- ****************************************************************/
- 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;
- }
- /**********************************************************************
- * 功能描述: 程序休眠
- * 輸入?yún)?shù): iCountMs-休眠時(shí)間(單位:ms)
- * 輸出參數(shù): 無
- * 返 回 值: 無
- * 其它說明: 無
- * 修改日期 版本號(hào) 修改人 修改內(nèi)容
- * ------------------------------------------------------------------
- * 20160811 V1.0 Zhou Zhaoxiong 創(chuàng)建
- ********************************************************************/
- 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); // 調(diào)用select函數(shù)阻塞程序
- }
程序運(yùn)行情況
我們將上面編寫好的QueueUse.c文件上傳到Linux機(jī)器上,使用“gcc -g -o QueueUseQueueUse.c”命令編譯之后,生成QueueUse文件。之后,執(zhí)行“QueueUse”命令,即可看到程序的運(yùn)行結(jié)果(結(jié)果會(huì)不斷地更新)如下:
- ~/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
我們看到,數(shù)據(jù)先是被加入到隊(duì)列中,然后再?gòu)年?duì)列中取出來。
程序說明
***,在本程序中,入隊(duì)列和出隊(duì)列是在同一個(gè)函數(shù)中完成的,但是,在實(shí)際開發(fā)項(xiàng)目的程序中,入隊(duì)列和出隊(duì)列一般是在不同的程序流程(兩個(gè)不同的線程)中完成的。
第二,本程序的數(shù)據(jù)入隊(duì)列操作是在EnQueue函數(shù)中完成的,數(shù)據(jù)出隊(duì)列操作是在DeQueue函數(shù)中完成的,全局變量g_tQueue用于存放需要處理的數(shù)據(jù)。
第三,在實(shí)際開發(fā)項(xiàng)目的程序中,有可能會(huì)有很多流程都會(huì)調(diào)用入隊(duì)列和出隊(duì)列的函數(shù),為了防止多個(gè)流程同時(shí)向隊(duì)列中加入數(shù)據(jù)或取出數(shù)據(jù),在EnQueue和DeQueue函數(shù)中使用了鎖操作。也就是說,在操作數(shù)據(jù)之前,先用pthread_mutex_lock函數(shù)執(zhí)行加鎖操作,在處理完數(shù)據(jù)之后,再用pthread_mutex_unlock函數(shù)執(zhí)行解鎖操作。
第四,在實(shí)際開發(fā)項(xiàng)目中,為了防止程序從隊(duì)列中取數(shù)據(jù)的速率過快而使得下游模塊處理不過來,我們常在從隊(duì)列取出數(shù)據(jù)之后發(fā)消息的流程中控制數(shù)據(jù)的發(fā)送速率,具體每秒鐘發(fā)送多少條可在配置文件中設(shè)置。
【本文是51CTO專欄作者周兆熊的原創(chuàng)作品,轉(zhuǎn)載請(qǐng)通過51CTO獲取作者授權(quán)】