带锁和条件变量的队列实现

队列的概念:先进先出,即每次加入的新数据都会放在队列的尾部,每次取出数据都为队列的头部。本文的队列的数据创建形式为链表。为了多线程使用防止冲突所以加入锁和条件变量以进行同步。下面用具体的代码来说明。
数据类型定义

typedef struct _node
{
    void *data;         //数据存放指针
    int size;           //数据大小
    struct _node *next; //下一个节点
} node_t;

typedef struct
{
    pthread_cond_t cond;   //内部条件变量
    pthread_mutex_t mutex; //内部锁
    node_t *head;          //队列的头指针
    int count;             //队列的可用node数量
} queue_t;

1. 队列的初始化:

/**
 * queue初始化
 * 包括条件变量,锁,count和head的初始化
*/
int queue_init(queue_t *queue)
{
    int ret = 0;

    ret = pthread_mutex_init(&queue->mutex, NULL);
    if (ret != 0)
    {
        perror("mutex init\n");
        return ret;
    }

    ret = pthread_cond_init(&queue->cond, NULL);
    if (ret != 0)
    {
        perror("cond init\n");
        return ret;
    }

    queue->count = 0;
    queue->head = NULL;
    return ret;
}

2. 向队列加入数据:queue_put会调用link_put_node,使用mutex和cond来同步

/**
 * 向link中加入node
*/
void link_put_node(node_t **head, const void *node, int size)
{
    node_t *temp = malloc(sizeof(node_t));
    node_t *ptr = *head;

    temp->data = malloc(size);
    memcpy(temp->data, node, size);
    temp->size = size;
    temp->next = NULL;

    if (*head == NULL)
    {
        *head = temp;
        return;
    }
    while (ptr->next != NULL)
    {
        ptr = ptr->next;
    }
    ptr->next = temp;
}

/**
 * 加入node到link中
*/
int queue_put(queue_t *queue, const void *node, int size)
{
    int ret = 0;

    pthread_mutex_lock(&queue->mutex);
    link_put_node(&queue->head, node, size);
    queue->count++;

    pthread_mutex_unlock(&queue->mutex);
    pthread_cond_signal(&queue->cond);

    return ret;
}

3.从队列拿数据:这里我实现了设置超时和不设置超时的两种方式,向队列放入数据也可以实现超时,参考下面的取数据超时很容易实现。

/**
 * 从link中获取node
 * 因为队列是先进先出,所以每次获取的都是头节点,然后将头结点后移作为新的头节点
*/
int link_get_node(node_t **head, void **node, int *size)
{
    int ret = 0;
    node_t *ptr = *head;

    if (ptr == NULL)
    {
        ret = -1;
        return ret;
    }

    //头指针后移
    *head = ptr->next;

    *size = ptr->size;
    *node = malloc(*size);
    memcpy(*node, ptr->data, *size);

    //释放原先的head内存
    free(ptr->data);
    free(ptr);

    return ret;
}
/**
 * 获取的node使用之后需要外部释放
*/
int queue_get(queue_t *queue, void **node, int *size)
{
    int ret = 0;

    while (1)
    {
        pthread_mutex_lock(&queue->mutex);
        if (queue->count <= 0)
        {
            ret = pthread_cond_wait(&queue->cond, &queue->mutex);
            if (ret == 0)
            {
                link_get_node(&queue->head, node, size);
                queue->count--;
                pthread_mutex_unlock(&queue->mutex);
                break;
            }
        }
        else
        {
            link_get_node(&queue->head, node, size);
            queue->count--;
            pthread_mutex_unlock(&queue->mutex);
            break;
        }
        pthread_mutex_unlock(&queue->mutex);
    }

    return ret;
}

/**
 * 获取的node使用之后需要外部释放
*/
int queue_get_timeout(queue_t *queue, void **node, int *size, int timeout_ms)
{
    int ret = 0;
    struct timespec now;

    pthread_mutex_lock(&queue->mutex);
    clock_gettime(CLOCK_REALTIME, &now);
    now.tv_sec += (timeout_ms / 1000);
    now.tv_nsec += (timeout_ms % 1000 * 1000000);
    if (queue->count <= 0)
    {
        ret = pthread_cond_timedwait(&queue->cond, &queue->mutex, &now);
        if (ret == 0)
        {
            link_get_node(&queue->head, node, size);
            queue->count--;
        }
        else if (ret == ETIMEDOUT)
        {
            printf("timeout\n");
        }
        else
        {
            printf("other error\n");
        }
    }
    else
    {
        link_get_node(&queue->head, node, size);
        queue->count--;
    }
    pthread_mutex_unlock(&queue->mutex);

    return ret;
}

4. 队列的销毁

/**
 * link的释放
*/
void link_destory(node_t **head)
{
    node_t *temp = NULL;

    while (*head != NULL)
    {
        temp = (*head)->next;
        free((*head)->data);
        free(*head);
        *head = temp;
    }
}
/**
 * queue的反初始化
 * 销毁条件变量,锁,link,count赋0
*/
int queue_deinit(queue_t *queue)
{
    int ret = 0;

    pthread_cond_destroy(&queue->cond);
    pthread_mutex_destroy(&queue->mutex);
    link_destory(&queue->head);
    queue->count = 0;

    return ret;
}

5. 最后附上完整代码以及测试实例:

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>

typedef struct _node
{
    void *data;         //数据存放指针
    int size;           //数据大小
    struct _node *next; //下一个节点
} node_t;

typedef struct
{
    pthread_cond_t cond;   //内部条件变量
    pthread_mutex_t mutex; //内部锁
    node_t *head;          //队列的头指针
    int count;             //队列的可用node数量
} queue_t;

/**
 * queue初始化
 * 包括条件变量,锁,count和head的初始化
*/
int queue_init(queue_t *queue)
{
    int ret = 0;

    ret = pthread_mutex_init(&queue->mutex, NULL);
    if (ret != 0)
    {
        perror("mutex init\n");
        return ret;
    }

    ret = pthread_cond_init(&queue->cond, NULL);
    if (ret != 0)
    {
        perror("cond init\n");
        return ret;
    }

    queue->count = 0;
    queue->head = NULL;
    return ret;
}

/**
 * link的释放
*/
void link_destory(node_t **head)
{
    node_t *temp = NULL;

    while (*head != NULL)
    {
        temp = (*head)->next;
        free((*head)->data);
        free(*head);
        *head = temp;
    }
}
/**
 * queue的反初始化
 * 销毁条件变量,锁,link,count赋0
*/
int queue_deinit(queue_t *queue)
{
    int ret = 0;

    pthread_cond_destroy(&queue->cond);
    pthread_mutex_destroy(&queue->mutex);
    link_destory(&queue->head);
    queue->count = 0;

    return ret;
}

/**
 * 从link中获取node
 * 因为队列是先进先出,所以每次获取的都是头节点,然后将头结点后移作为新的头节点
*/
int link_get_node(node_t **head, void **node, int *size)
{
    int ret = 0;
    node_t *ptr = *head;

    if (ptr == NULL)
    {
        ret = -1;
        return ret;
    }

    //头指针后移
    *head = ptr->next;

    *size = ptr->size;
    *node = malloc(*size);
    memcpy(*node, ptr->data, *size);

    //释放原先的head内存
    free(ptr->data);
    free(ptr);

    return ret;
}
/**
 * 获取的node使用之后需要外部释放
*/
int queue_get(queue_t *queue, void **node, int *size)
{
    int ret = 0;

    while (1)
    {
        pthread_mutex_lock(&queue->mutex);
        if (queue->count <= 0)
        {
            ret = pthread_cond_wait(&queue->cond, &queue->mutex);
            if (ret == 0)
            {
                link_get_node(&queue->head, node, size);
                queue->count--;
                pthread_mutex_unlock(&queue->mutex);
                break;
            }
        }
        else
        {
            link_get_node(&queue->head, node, size);
            queue->count--;
            pthread_mutex_unlock(&queue->mutex);
            break;
        }
        pthread_mutex_unlock(&queue->mutex);
    }

    return ret;
}

/**
 * 获取的node使用之后需要外部释放
*/
int queue_get_timeout(queue_t *queue, void **node, int *size, int timeout_ms)
{
    int ret = 0;
    struct timespec now;

    pthread_mutex_lock(&queue->mutex);
    clock_gettime(CLOCK_REALTIME, &now);
    now.tv_sec += (timeout_ms / 1000);
    now.tv_nsec += (timeout_ms % 1000 * 1000000);
    if (queue->count <= 0)
    {
        ret = pthread_cond_timedwait(&queue->cond, &queue->mutex, &now);
        if (ret == 0)
        {
            link_get_node(&queue->head, node, size);
            queue->count--;
        }
        else if (ret == ETIMEDOUT)
        {
            printf("timeout\n");
        }
        else
        {
            printf("other error\n");
        }
    }
    else
    {
        link_get_node(&queue->head, node, size);
        queue->count--;
    }
    pthread_mutex_unlock(&queue->mutex);

    return ret;
}

/**
 * 向link中加入node
*/
​

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>

typedef struct _node
{
    void *data;         //数据存放指针
    int size;           //数据大小
    struct _node *next; //下一个节点
} node_t;

typedef struct
{
    pthread_cond_t cond;   //内部条件变量
    pthread_mutex_t mutex; //内部锁
    node_t *head;          //队列的头指针
    int count;             //队列的可用node数量
} queue_t;

/**
 * queue初始化
 * 包括条件变量,锁,count和head的初始化
*/
int queue_init(queue_t *queue)
{
    int ret = 0;

    ret = pthread_mutex_init(&queue->mutex, NULL);
    if (ret != 0)
    {
        perror("mutex init\n");
        return ret;
    }

    ret = pthread_cond_init(&queue->cond, NULL);
    if (ret != 0)
    {
        perror("cond init\n");
        return ret;
    }

    queue->count = 0;
    queue->head = NULL;
    return ret;
}

/**
 * link的释放
*/
void link_destory(node_t **head)
{
    node_t *temp = NULL;

    while (*head != NULL)
    {
        temp = (*head)->next;
        free((*head)->data);
        free(*head);
        *head = temp;
    }
}
/**
 * queue的反初始化
 * 销毁条件变量,锁,link,count赋0
*/
int queue_deinit(queue_t *queue)
{
    int ret = 0;

    pthread_cond_destroy(&queue->cond);
    pthread_mutex_destroy(&queue->mutex);
    link_destory(&queue->head);
    queue->count = 0;

    return ret;
}

/**
 * 从link中获取node
 * 因为队列是先进先出,所以每次获取的都是头节点,然后将头结点后移作为新的头节点
*/
int link_get_node(node_t **head, void **node, int *size)
{
    int ret = 0;
    node_t *ptr = *head;

    if (ptr == NULL)
    {
        ret = -1;
        return ret;
    }

    //头指针后移
    *head = ptr->next;

    *size = ptr->size;
    *node = malloc(*size);
    memcpy(*node, ptr->data, *size);

    //释放原先的head内存
    free(ptr->data);
    free(ptr);

    return ret;
}
/**
 * 获取的node使用之后需要外部释放
*/
int queue_get(queue_t *queue, void **node, int *size)
{
    int ret = 0;

    while (1)
    {
        pthread_mutex_lock(&queue->mutex);
        if (queue->count <= 0)
        {
            ret = pthread_cond_wait(&queue->cond, &queue->mutex);
            if (ret == 0)
            {
                link_get_node(&queue->head, node, size);
                queue->count--;
                pthread_mutex_unlock(&queue->mutex);
                break;
            }
        }
        else
        {
            link_get_node(&queue->head, node, size);
            queue->count--;
            pthread_mutex_unlock(&queue->mutex);
            break;
        }
        pthread_mutex_unlock(&queue->mutex);
    }

    return ret;
}

/**
 * 获取的node使用之后需要外部释放
*/
int queue_get_timeout(queue_t *queue, void **node, int *size, int timeout_ms)
{
    int ret = 0;
    struct timespec now;

    pthread_mutex_lock(&queue->mutex);
    clock_gettime(CLOCK_REALTIME, &now);
    now.tv_sec += (timeout_ms / 1000);
    now.tv_nsec += (timeout_ms % 1000 * 1000000);
    if (queue->count <= 0)
    {
        ret = pthread_cond_timedwait(&queue->cond, &queue->mutex, &now);
        if (ret == 0)
        {
            link_get_node(&queue->head, node, size);
            queue->count--;
        }
        else if (ret == ETIMEDOUT)
        {
            printf("timeout\n");
        }
        else
        {
            printf("other error\n");
        }
    }
    else
    {
        link_get_node(&queue->head, node, size);
        queue->count--;
    }
    pthread_mutex_unlock(&queue->mutex);

    return ret;
}

/**
 * 向link中加入node
*/
void link_put_node(node_t **head, const void *node, int size)
{
    node_t *temp = malloc(sizeof(node_t));
    node_t *ptr = *head;

    temp->data = malloc(size);
    memcpy(temp->data, node, size);
    temp->size = size;
    temp->next = NULL;

    if (*head == NULL)
    {
        *head = temp;
        return;
    }
    while (ptr != NULL)
    {
        ptr = ptr->next;
    }
    ptr = temp;
}

/**
 * 加入node到link中
*/
int queue_put(queue_t *queue, const void *node, int size)
{
    int ret = 0;

    pthread_mutex_lock(&queue->mutex);
    link_put_node(&queue->head, node, size);
    queue->count++;

    pthread_mutex_unlock(&queue->mutex);
    pthread_cond_signal(&queue->cond);

    return ret;
}

void *thread_handle(void *arg)
{
    queue_t *queue = (queue_t *)arg;
    int count = 0;
    int ret = 0;
    int *data = NULL;
    int size = 0;

    while (1)
    {
        ret = queue_get_timeout(queue, (void **)&data, &size, 1000);
        if (ret == 0)
        {
            printf("data:%d,size:%d\n", *data, size);
            free(data);
            data = NULL;
            size = 0;
        }
    }
    return arg;
}

int main()
{
    pthread_t pthread;
    queue_t queue;
    int time_sec = 1;

    queue_init(&queue);
    pthread_create(&pthread, NULL, thread_handle, (void *)&queue);

    while (1)
    {
        sleep(time_sec);
        time_sec++;
        queue_put(&queue, (const void *)&time_sec, sizeof(time_sec));
    }

    return 0;
}

[点击并拖拽以移动]
​

/**
 * 加入node到link中
*/
int queue_put(queue_t *queue, const void *node, int size)
{
    int ret = 0;

    pthread_mutex_lock(&queue->mutex);
    link_put_node(&queue->head, node, size);
    queue->count++;

    pthread_mutex_unlock(&queue->mutex);
    pthread_cond_signal(&queue->cond);

    return ret;
}

void *thread_handle(void *arg)
{
    queue_t *queue = (queue_t *)arg;
    int count = 0;
    int ret = 0;
    int *data = NULL;
    int size = 0;

    while (1)
    {
        ret = queue_get_timeout(queue, (void **)&data, &size, 1000);
        if (ret == 0)
        {
            printf("data:%d,size:%d\n", *data, size);
            free(data);
            data = NULL;
            size = 0;
        }
    }
    return arg;
}

int main()
{
    pthread_t pthread;
    queue_t queue;
    int time_sec = 1;

    queue_init(&queue);
    pthread_create(&pthread, NULL, thread_handle, (void *)&queue);

    while (1)
    {
        sleep(time_sec);
        time_sec++;
        queue_put(&queue, (const void *)&time_sec, sizeof(time_sec));
    }

    return 0;
}

编译:gcc queue.c -lpthread

运行:./a.out

程序的输出如下:

data:2,size:4
timeout
data:3,size:4
timeout
timeout
data:4,size:4
timeout
timeout
timeout
data:5,size:4
timeout
timeout
timeout
timeout
data:6,size:4
timeout
timeout
timeout
^C

最后希望本文能让读者有所得,谢谢!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值