Linux c实现一个线程安全的环形队列

ringQueue.h

#ifndef RINGQUEUE_H
#define RINGQUEUE_H
 
#ifdef __cplusplus
extern "C"
{
#endif
 
#include <stdbool.h>
#include <pthread.h>
#include <stdint.h>
 
    typedef struct rQueue_data
    {
        void *buffer;
        uint32_t len;
    } rQueue_data;
 
    typedef struct ringQueue
    {
        uint32_t front; // 头指针
        uint32_t rear;  // 尾指针,若队列不空,指向队列尾元素的下一个位置
        pthread_mutex_t mutex;
        uint32_t max_queueLen;   // 队列的最大长度
        uint32_t max_dataLen;    // 数据的最大长度
        rQueue_data data[]; // 存储空间
    } ringQueue;
 
    /**
     * @description: 初始化队列,分配内存
     * @param max_qLen  队列的最大长度
     * @param max_dLen 数据的最大长度,即rQueue_data->buffer分配的内存大小,单位:字节
     * @return  队列指针
     */
    ringQueue *rQueue_init(uint32_t max_qLen, uint32_t max_dLen);
 
    /**
     * @description: 入队
     * @param *q 队列指针
     * @param *e 入队元素
     * @return 成功:0  失败:-1
     */
    int rQueue_en(ringQueue *q, const rQueue_data *e);
 
    /**
     * @description: 出队
     * @param *q 队列指针
     * @param *e 出队元素,e->buffer需要在外部申请内存,e->len需要初始化为e->buffer的内存大小
     *           出队成功,e->len会被赋值为实际出队的数据大小,出队失败,e->len会被赋值为0
     * @return 成功:0  失败:-1
     */
    int rQueue_de(ringQueue *q, rQueue_data *e);
 
    // 返回队列的元素个数,也就是队列的当前长度
    /**
     * @description: 返回队列的当前长度
     * @param *q 队列指针
     * @return  成功:队列长度,失败:-1
     */
    int rQueue_length(ringQueue *q);
 
    /**
     * @description: 判断队列是否为空
     * @param *q 队列指针
     * @return  true: 队列为空或q为NULL   false: 非空
     */
    bool rQueue_isEmpty(ringQueue *q);
 
    /**
     * @description: 清空队列
     * @param *q 队列指针
     * @return 成功:0  失败:-1
     */
    int rQueue_clear(ringQueue *q);
 
    /**
     * @description: 销毁队列
     * @param **q 队列指针的指针
     * @return
     */
    void rQueue_destroy(ringQueue **q);
 
#ifdef __cplusplus
}
#endif
 
#endif /* RINGQUEUE_H */

ringQueue.c

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "ringQueue.h"

ringQueue *rQueue_init(uint32_t max_qLen, uint32_t max_dLen)
{
    size_t n = sizeof(ringQueue) + sizeof(rQueue_data) * max_qLen;
    ringQueue *q = (ringQueue *)malloc(n);
    if (q == NULL)
    {
        printf("%d: rQueue_init err, malloc fail\n", __LINE__);
        return NULL;
    }
    memset(q, 0, n);
    for (uint32_t i = 0; i < max_qLen; i++)
    {
        q->data[i].buffer = malloc(max_dLen);
        if (q->data[i].buffer == NULL)
        {
            printf("%d: rQueue_init err, malloc fail\n", __LINE__);
            // 释放前面已经申请的内存
            for (uint32_t j = 0; j < i; j++)
            {
                free(q->data[j].buffer);
            }
            free(q);
            return NULL;
        }
        memset(q->data[i].buffer, 0, max_dLen);
        q->data[i].len = 0;
    }
    q->max_queueLen = max_qLen;
    q->max_dataLen = max_dLen;
    pthread_mutex_init(&q->mutex, NULL);

    return q;
}

int rQueue_en(ringQueue *q, const rQueue_data *e)
{
    int ret = -1;

    pthread_mutex_lock(&q->mutex);
    if (q == NULL || e == NULL || e->buffer == NULL)
    {
        goto end;
    }
    if ((q->rear + 1) % q->max_queueLen == q->front) // 队列满的判断
    {
        printf("queue is full\n");
        goto end;
    }
    if (e->len > q->max_dataLen)
    {
        printf("rQueue_en err, e->len is too large, e->len: %d byte, max: %d byte\n",
               e->len, q->max_dataLen);
        goto end;
    }
    memcpy(q->data[q->rear].buffer, e->buffer, e->len);
    q->data[q->rear].len = e->len;
    q->rear = (q->rear + 1) % q->max_queueLen; // rear 指针向后移一位置,若到最后则转到数组头部
    ret = 0;
end:
    pthread_mutex_unlock(&q->mutex);
    return ret;
}

// 出队
int rQueue_de(ringQueue *q, rQueue_data *e)
{
    int ret = -1;

    pthread_mutex_lock(&q->mutex);
    if (q == NULL || e == NULL || e->buffer == NULL)
    {
        goto end;
    }
    if (q->front == q->rear) // 队列空的判断
    {
        printf("queue is empty\n");
        goto end;
    }
    if (e->len < q->data[q->front].len)
    {
        printf("rQueue_de err, e->len is too small, e->len: %d byte, min: %d byte\n",
               e->len, q->data[q->front].len);
        goto end;
    }
    memcpy(e->buffer, q->data[q->front].buffer, q->data[q->front].len);
    e->len = q->data[q->front].len;
    memset(q->data[q->front].buffer, 0, q->max_dataLen);
    q->data[q->front].len = 0;
    q->front = (q->front + 1) % q->max_queueLen; // front 指针向后移一位置,若到最后则转到数组头部
    ret = 0;
end:
    if (ret == -1)
    {
        e->len = 0;
    }
    pthread_mutex_unlock(&q->mutex);
    return ret;
}

int rQueue_length(ringQueue *q)
{
    pthread_mutex_lock(&q->mutex);
    if (q == NULL)
    {
        pthread_mutex_unlock(&q->mutex);
        return -1;
    }
    int len = (q->rear - q->front + q->max_queueLen) % q->max_queueLen;
    pthread_mutex_unlock(&q->mutex);

    return len;
}

bool rQueue_isEmpty(ringQueue *q)
{
    bool ret = false;

    pthread_mutex_lock(&q->mutex);
    if (q == NULL)
    {
        printf("rQueue_isEmpty err, q is NULL\n");
        pthread_mutex_unlock(&q->mutex);
        return true;
    }
    if (q->front == q->rear)
    {
        ret = true;
    }
    pthread_mutex_unlock(&q->mutex);

    return ret;
}

int rQueue_clear(ringQueue *q)
{
    pthread_mutex_lock(&q->mutex);
    if (q == NULL)
    {
        pthread_mutex_unlock(&q->mutex);
        return -1;
    }
    for (uint32_t i = 0; i < q->max_queueLen; i++)
    {
        memset(q->data[i].buffer, 0, q->max_dataLen);
        q->data[i].len = 0;
    }
    q->front = 0;
    q->rear = 0;
    pthread_mutex_unlock(&q->mutex);

    return 0;
}

void rQueue_destroy(ringQueue **q)
{
    if (q == NULL)
    {
        return;
    }
    for (uint32_t i = 0; i < (*q)->max_queueLen; i++)
    {
        free((*q)->data[i].buffer);
    }
    pthread_mutex_destroy(&((*q)->mutex));
    free(*q);
    *q = NULL;
}

测试:

#include <stdio.h>
#include <string.h>
#include "ringQueue.h"

int main(void)
{
    ringQueue *q;

    q = rQueue_init(5, 10);
    if (q == NULL)
    {
        printf("rQueue_init fail.\n");
        return -1;
    }

    char str[10] = "";
    for (int i = 0; i < 4; i++)
    {
        char temp[2];
        rQueue_data e;

        sprintf(temp, "%d", i);
        strcat(str, temp);
        printf("str: %s\n", str);
        e.buffer = str;
        e.len = strlen(str) + 1;
        rQueue_en(q, &e);
    }

    printf("rQueue_length: %d\n", rQueue_length(q));
    //rQueue_clear(q);
    if (rQueue_isEmpty(q))
    {
        printf("queue empty\n");
    }
    else
    {
        printf("queue not empty\n");
    }

    memset(str, 0, sizeof(str));
    for (int i = 0; i < 4; i++)
    {
        rQueue_data e;

        e.buffer = str;
        e.len = sizeof(str);
        rQueue_de(q, &e);
        printf("e.buffer: %s    e.len: %d\n", (char *)e.buffer, e.len);
    }

    rQueue_destroy(&q);
    if(q == NULL)
    {
        printf("queue destroy success.\n");
    }

    return 0;
}

输出结果:

str: 0
str: 01
str: 012
str: 0123
rQueue_length: 4
queue not empty
e.buffer: 0    e.len: 2
e.buffer: 01    e.len: 3
e.buffer: 012    e.len: 4
e.buffer: 0123    e.len: 5
queue destroy success.

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值