Linux下入队列和出队列操作的C代码示例

简介: 本文用实际的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函数执行解锁操作。

第四,在实际开发项目中,为了防止程序从队列中取数据的速率过快而使得下游模块处理不过来,我们常在从队列取出数据之后发消息的流程中控制数据的发送速率,具体每秒钟发送多少条可在配置文件中设置。

目录
相关文章
|
2月前
|
Unix Linux
Linux | Rsync 命令:16 个实际示例(下)
Linux | Rsync 命令:16 个实际示例(下)
38 3
Linux | Rsync 命令:16 个实际示例(下)
|
28天前
|
Ubuntu Linux Shell
Linux 系统中的代码类型或脚本类型内容
在 Linux 系统中,代码类型多样,包括 Shell 脚本、配置文件、网络配置、命令行工具和 Cron 定时任务。这些代码类型广泛应用于系统管理、自动化操作、网络配置和定期任务,掌握它们能显著提高系统管理和开发的效率。
|
2月前
|
安全 Linux Shell
Linux | Rsync 命令:16 个实际示例(上)
Linux | Rsync 命令:16 个实际示例(上)
75 0
Linux | Rsync 命令:16 个实际示例(上)
|
2月前
|
Linux C语言 C++
vsCode远程执行c和c++代码并操控linux服务器完整教程
这篇文章提供了一个完整的教程,介绍如何在Visual Studio Code中配置和使用插件来远程执行C和C++代码,并操控Linux服务器,包括安装VSCode、安装插件、配置插件、配置编译工具、升级glibc和编写代码进行调试的步骤。
281 0
vsCode远程执行c和c++代码并操控linux服务器完整教程
|
3月前
|
Linux Shell
Linux 中 Tail 命令的 9 个实用示例
Linux 中 Tail 命令的 9 个实用示例
108 6
Linux 中 Tail 命令的 9 个实用示例
|
3月前
|
Java Linux Python
Linux环境下 代码java调用python出错
Linux环境下 代码java调用python出错
61 3
|
3月前
|
Linux Shell Python
9-7|salt代码在linux机子那个目录
9-7|salt代码在linux机子那个目录
|
4月前
|
NoSQL Linux 编译器
内核实验(一):使用QEMU+GDB断点调试Linux内核代码
如何配置环境并使用QEMU虚拟机结合GDB进行Linux内核代码的断点调试,包括安装QEMU、交叉编译工具链,编译内核以及通过GDB远程连接进行调试的详细步骤。
169 0
内核实验(一):使用QEMU+GDB断点调试Linux内核代码
|
3月前
|
Linux 开发者 Python
从Windows到Linux,Python系统调用如何让代码飞翔🚀
【9月更文挑战第10天】在编程领域,跨越不同操作系统的障碍是常见挑战。Python凭借其“编写一次,到处运行”的理念,显著简化了这一过程。通过os、subprocess、shutil等标准库模块,Python提供了统一的接口,自动处理底层差异,使代码在Windows和Linux上无缝运行。例如,`open`函数在不同系统中以相同方式操作文件,而`subprocess`模块则能一致地执行系统命令。此外,第三方库如psutil进一步增强了跨平台能力,使开发者能够轻松编写高效且易维护的代码。借助Python的强大系统调用功能,跨平台编程变得简单高效。
50 0
|
3月前
|
机器学习/深度学习 Linux 开发工具
Linux内核开发流程指南 - 5. 编写正确的代码【ChatGPT】
Linux内核开发流程指南 - 5. 编写正确的代码【ChatGPT】