生产者-消费者队列中的奇怪死锁
Strange deadlock in producer-consumer queue
使用 C 的 pthread 库,我正在尝试实现一个简单的生产者-消费者模式。
生产者生成随机数并将它们放入这样的队列中
typedef struct {
int q[MAX_QUEUE];
int head;
int tail;
} queue;
消费者只需一个一个地获取数字并将它们打印到标准输出。同步是通过一个 mutex
和两个条件变量完成的:empty_queue
(如果队列为空则暂停消费者)和 full_queue
(如果队列已满则暂停生产者)。问题是两个线程在到达 MAX_QUEUE
个元素 produced/consumed 时都挂起,因此它们进入了死锁状态。我认为我做的一切都是正确的,我不知道我做错了什么。
制作人:
void* producer(void* args) {
unsigned seed = time(NULL);
int random;
queue *coda = (queue *) args;
while(1) {
Pthread_mutex_lock(&queue_lock);
while(coda->head == MAX_QUEUE-1) { // Full Queue
printf("Suspending producer\n");
fflush(stdout);
Pthread_cond_wait(&full_queue, &queue_lock);
}
random = rand_r(&seed) % 21;
enqueue(coda, random);
Pthread_cond_signal(&empty_queue);
Pthread_mutex_unlock(&queue_lock);
sleep(1);
}
return NULL;
}
消费者:
void* consumer(void* args) {
queue *coda = (queue *) args;
int elem;
while(1) {
Pthread_mutex_lock(&queue_lock);
while(coda->head == coda->tail) { // Empty Queue
printf("Suspending Consumer\n");
fflush(stdout);
Pthread_cond_wait(&empty_queue, &queue_lock);
}
elem = dequeue(coda);
printf("Found %i\n",elem);
Pthread_cond_signal(&full_queue);
Pthread_mutex_unlock(&queue_lock);
}
return NULL;
}
Enqueue/Dequeue套路
static void enqueue(queue *q, int elem) {
q->q[(q->tail)] = elem;
(q->tail)++;
if(q->tail == MAX_QUEUE)
q->tail = 0;
}
static int dequeue(queue *q) {
int elem = q->q[(q->head)];
(q->head)++;
if(q->head == MAX_QUEUE)
q->head = 0;
return elem;
}
Pthread_* 只是标准 pthread_* 库函数的包装函数。
输出(MAX_QUEUE = 10):
Suspending Consumer
Found 16
Suspending Consumer
Found 7
Suspending Consumer
Found 5
Suspending Consumer
Found 6
Suspending Consumer
Found 17
Suspending Consumer
Found 1
Suspending Consumer
Found 12
Suspending Consumer
Found 14
Suspending Consumer
Found 11
Suspending Consumer
Suspending producer
coda->head == MAX_QUEUE-1
这不会检查队列是否已满。描述队列状态的变量有两个,head
和tail
.
coda->head == coda->tail
这正确地检查了队列是否为空。请注意在检查中如何使用这两个变量。
使用 C 的 pthread 库,我正在尝试实现一个简单的生产者-消费者模式。
生产者生成随机数并将它们放入这样的队列中
typedef struct {
int q[MAX_QUEUE];
int head;
int tail;
} queue;
消费者只需一个一个地获取数字并将它们打印到标准输出。同步是通过一个 mutex
和两个条件变量完成的:empty_queue
(如果队列为空则暂停消费者)和 full_queue
(如果队列已满则暂停生产者)。问题是两个线程在到达 MAX_QUEUE
个元素 produced/consumed 时都挂起,因此它们进入了死锁状态。我认为我做的一切都是正确的,我不知道我做错了什么。
制作人:
void* producer(void* args) {
unsigned seed = time(NULL);
int random;
queue *coda = (queue *) args;
while(1) {
Pthread_mutex_lock(&queue_lock);
while(coda->head == MAX_QUEUE-1) { // Full Queue
printf("Suspending producer\n");
fflush(stdout);
Pthread_cond_wait(&full_queue, &queue_lock);
}
random = rand_r(&seed) % 21;
enqueue(coda, random);
Pthread_cond_signal(&empty_queue);
Pthread_mutex_unlock(&queue_lock);
sleep(1);
}
return NULL;
}
消费者:
void* consumer(void* args) {
queue *coda = (queue *) args;
int elem;
while(1) {
Pthread_mutex_lock(&queue_lock);
while(coda->head == coda->tail) { // Empty Queue
printf("Suspending Consumer\n");
fflush(stdout);
Pthread_cond_wait(&empty_queue, &queue_lock);
}
elem = dequeue(coda);
printf("Found %i\n",elem);
Pthread_cond_signal(&full_queue);
Pthread_mutex_unlock(&queue_lock);
}
return NULL;
}
Enqueue/Dequeue套路
static void enqueue(queue *q, int elem) {
q->q[(q->tail)] = elem;
(q->tail)++;
if(q->tail == MAX_QUEUE)
q->tail = 0;
}
static int dequeue(queue *q) {
int elem = q->q[(q->head)];
(q->head)++;
if(q->head == MAX_QUEUE)
q->head = 0;
return elem;
}
Pthread_* 只是标准 pthread_* 库函数的包装函数。 输出(MAX_QUEUE = 10):
Suspending Consumer
Found 16
Suspending Consumer
Found 7
Suspending Consumer
Found 5
Suspending Consumer
Found 6
Suspending Consumer
Found 17
Suspending Consumer
Found 1
Suspending Consumer
Found 12
Suspending Consumer
Found 14
Suspending Consumer
Found 11
Suspending Consumer
Suspending producer
coda->head == MAX_QUEUE-1
这不会检查队列是否已满。描述队列状态的变量有两个,head
和tail
.
coda->head == coda->tail
这正确地检查了队列是否为空。请注意在检查中如何使用这两个变量。