队列的概念:先进先出,即每次加入的新数据都会放在队列的尾部,每次取出数据都为队列的头部。本文的队列的数据创建形式为链表。为了多线程使用防止冲突所以加入锁和条件变量以进行同步。下面用具体的代码来说明。
数据类型定义:
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
最后希望本文能让读者有所得,谢谢!