利用条件变量实现的多线程队列pqueue,
原理:
1. 在pqueue结构里定义了两个条件变量m_full和m_free,两个计数器m_freewait和m_fullwait。
2. 生产者线程向队列插入数据前,判断队列是否满,如果满则让该线程等待在m_full,等待消费者线程从队列取元素,计数器m_fullwait自增,用来表示等待m_full的生产者线程数。
3. 生产者线程向队列中写入数据后,检测m_freewait计数器看是否有线程等待在m_free,如果有,则pthread_cond_signal(&m_free)发送一个信号,唤醒一个等待在m_free的线程,然后m_freewait自减。
4. 消费者线程从队列中取数据前,判断队列是否空,如果空则该线程等待在m_free;等待生产者线程往队列中存数据,计数器m_freewait自增,表示等待m_free的消费者线程数
5. 消费者线程从队列中取出数据后,检测m_fullwait计数器看是否有线程等待在m_full,如果与,则pthread_cond_signal(&m_full)发动一个信号,唤醒一个等待在m_full的线程,然后m_fullwait自减。
代码如下:
pqueue.h
#ifndef _THREAD_QUEUE_H_
#define _THREAD_QUEUE_H_
#include <stdlib.h>
#include <pthread.h>
typedef struct _node {
int m_data;
struct _node* m_next;
} node_t;
typedef struct _queue {
node_t *m_head;
node_t **m_tail;
int m_size;
int m_maxsize;
int m_freewait; // the number of waiting thread when queue is free
int m_fullwait; // the number of waiting thread when queue is full
pthread_cond_t m_full;
pthread_cond_t m_free;
pthread_mutex_t m_lock;
} queue_t;
void* queue_init (int size);
void queue_del (void* que);
int queue_put (void* que, int data);
int queue_get (void* que, int* data);
#endif
pqueue.c
#include "pqueue.h"
#include <assert.h>
void* queue_init (int size) {
queue_t* q;
assert (size > 0);
q = (queue_t*)malloc(sizeof(queue_t));
q->m_head = 0;
q->m_tail = &(q->m_head);
q->m_size = 0;
q->m_maxsize = size;
q->m_freewait = 0;
q->m_fullwait = 0;
pthread_cond_init (&(q->m_full),0);
pthread_cond_init (&(q->m_free),0);
pthread_mutex_init (&(q->m_lock),0);
return q;
}
void queue_del (void* que) {
queue_t* queue = (queue_t*) que;
node_t* p, *q;
pthread_mutex_lock (&(queue->m_lock));
assert (!(queue->m_freewait));
assert (!(queue->m_fullwait));
for (p = queue->m_head; p; p = q) {
q = p->m_next;
free (p);
}
pthread_mutex_unlock (&(queue->m_lock));
pthread_mutex_destroy (&(queue->m_lock));
pthread_cond_destroy (&(queue->m_free));
pthread_cond_destroy (&(queue->m_full));
free (queue);
}
int queue_put (void* que, int data) {
queue_t* queue = (queue_t*)que;
node_t* node = (node_t*)malloc (sizeof(node_t));
node->m_data = data;
node->m_next = 0;
pthread_mutex_lock (&(queue->m_lock));
while (queue->m_size >= queue->m_maxsize) {
queue->m_fullwait++;
pthread_cond_wait (&(queue->m_full),&(queue->m_lock));
}
queue->m_size ++;
*(queue->m_tail) = node;
if (queue->m_freewait > 0) {
pthread_cond_signal (&(queue->m_free));
queue->m_freewait --;
}
pthread_mutex_unlock (&(queue->m_lock));
return 0;
}
int queue_get (void* que, int* data) {
queue_t* queue = (queue_t*)que;
node_t* node;
pthread_mutex_lock (&(queue->m_lock));
while (queue->m_size == 0) {
queue->m_freewait ++;
pthread_cond_wait (&(queue->m_free), &(queue->m_lock));
}
node = queue->m_head;
queue->m_head = node->m_next;
if (!queue->m_head) {
queue->m_tail = &(queue->m_head);
}
queue->m_size --;
if (queue->m_fullwait > 0) {
pthread_cond_signal (&(queue->m_full));
queue->m_fullwait--;
}
pthread_mutex_unlock (&(queue->m_lock));
if (data) {
*data = node->m_data;
}
free (node);
}
下面是一个例子,主线程做生产者,15个子线程做做消费者
#include <stdio.h>
#include "pqueue.h"
pthread_t tarr[15];
queue_t *g_queue;
void* thr_fn (void* arg) {
pthread_t tid = pthread_self();
for (;;) {
int data;
queue_get (g_queue, &data);
printf ("tid = %u, data = %d\n",(unsigned int)tid, data);
sleep (1);
}
}
int main () {
int i = 0;
g_queue = queue_init (30);
for (i = 0; i < 15; ++i) {
pthread_create (&tarr[i],0, thr_fn, 0);
}
for (;;) {
queue_put (g_queue, rand());
}
}