提问人:Samuel Afon 提问时间:10/28/2023 更新时间:10/28/2023 访问量:76
使用条件变量的正确方法是什么?
What is the proper way to use conditional variables?
问:
我的赋值提供的运行代码在运行时使用高百分比的 CPU。目标是通过在生产者消费者问题中实现条件变量来减少该数量。
我按照我所能提供的说明进行操作,在互斥锁解锁之前在生产者端添加一个 wait() 函数,然后从 if-else 语句的 else 部分发送信号。
// if buffer is full, release mutex lock and check again
if (shared_count == NITEMS){
// wait when full
pthread_cond_wait(&cond1, &mutex);
pthread_mutex_unlock(&mutex);
}
else{
//signal
pthread_cond_signal(&cond1);
break;
}
我在消费者方面也做了同样的事情。
问题是我的整体代码不再提供任何输出。
我在下面包含了完整的代码,以防万一
/* minor3.c - using producer-consumer paradigm. */
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define NITEMS 10 // number of items in shared buffer
// shared variables
char shared_buffer[NITEMS]; // echo buffer
int shared_count; // item count
pthread_mutex_t mutex; // pthread mutex
unsigned int prod_index = 0; // producer index into shared buffer
unsigned int cons_index = 0; // consumer index into shard buffer
// function prototypes
void * producer(void *arg);
void * consumer(void *arg);
// Consumer variables
pthread_cond_t cond1 = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond2 = PTHREAD_COND_INITIALIZER;
int main()
{
pthread_t prod_tid, cons_tid1, cons_tid2;
// initialize pthread variables
pthread_mutex_init(&mutex, NULL);
// initialize condition variables
pthread_cond_init(&cond1, NULL);
pthread_cond_init(&cond2, NULL);
// start producer thread
pthread_create(&prod_tid, NULL, producer, NULL);
// start consumer threads
pthread_create(&cons_tid1, NULL, consumer, NULL);
pthread_create(&cons_tid2, NULL, consumer, NULL);
// wait for threads to finish
pthread_join(prod_tid, NULL);
pthread_join(cons_tid1, NULL);
pthread_join(cons_tid2, NULL);
// clean up
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond1);
pthread_cond_destroy(&cond2);
return 0;
}
// producer thread executes this function
void * producer(void *arg)
{
char key;
printf("Enter text for producer to read and consumer to print, use Ctrl-C to exit.\n\n");
// this loop has the producer read data in from stdin and place the read data on the shared buffer
while (1)
{
// read input key
scanf("%c", &key);
// this loop is used to poll the shared buffer to see if it is full:
// -- if full, unlock and loop again to keep polling
// -- if not full, keep locked and proceed to place character on shared buffer
while (1)
{
// acquire mutex lock
pthread_mutex_lock(&mutex);
// if buffer is full, release mutex lock and check again
if (shared_count == NITEMS){
// wait when full
pthread_cond_wait(&cond1, &mutex);
pthread_mutex_unlock(&mutex);
}
else{
//signal
pthread_cond_signal(&cond1);
break;
}
}
// store key in shared buffer
shared_buffer[prod_index] = key;
// update shared count variable
shared_count++;
// update producer index
if (prod_index == NITEMS - 1)
prod_index = 0;
else
prod_index++;
// release mutex lock
pthread_mutex_unlock(&mutex);
}
return NULL;
}
// consumer thread executes this function
void * consumer(void *arg)
{
char key;
long unsigned int id = (long unsigned int)pthread_self();
// this loop has the consumer get data from the shared buffer and print to stdout
while (1)
{
// this loop is used to poll the shared buffer to see if it is empty:
// -- if empty, unlock and loop again to keep polling
// -- if not empty, keep locked and proceed to get character from shared buffer
while (1)
{
// acquire mutex lock
pthread_mutex_lock(&mutex);
// if buffer is empty, release mutex lock and check again
if (shared_count == 0){
pthread_cond_wait(&cond2, &mutex);
pthread_mutex_unlock(&mutex);
}
else{
pthread_cond_signal(&cond2);
break;
}
}
// read key from shared buffer
key = shared_buffer[cons_index];
// echo key
printf("consumer %lu: %c\n", (long unsigned int) id, key);
// update shared count variable
shared_count--;
// update consumer index
if (cons_index == NITEMS - 1)
cons_index = 0;
else
cons_index++;
// release mutex lock
pthread_mutex_unlock(&mutex);
}
return NULL;
}
答:
4赞
David Schwartz
10/28/2023
#1
你有两个错误。
首先,您永远不会设置为零。您可以增加、减少和测试它。但你永远不会初始化它。shared_count
其次,消费者向消费者发出条件变量的信号,反之亦然。您需要消费者向生产者发出信号,反之亦然!
最后,虽然这不是一个错误,但你的循环不必要地解锁了互斥锁,只是为了在下一次迭代时立即再次锁定它。在内部循环之外解锁互斥锁更有意义。
下面是修复了错误和更传统的循环结构的代码:
/* minor3.c - using producer-consumer paradigm. */
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define NITEMS 10 // number of items in shared buffer
// shared variables
char shared_buffer[NITEMS]; // echo buffer
int shared_count = 0; // item count
pthread_mutex_t mutex; // pthread mutex
unsigned int prod_index = 0; // producer index into shared buffer
unsigned int cons_index = 0; // consumer index into shard buffer
// function prototypes
void * producer(void *arg);
void * consumer(void *arg);
// Consumer variables
pthread_cond_t cond1 = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond2 = PTHREAD_COND_INITIALIZER;
int main()
{
pthread_t prod_tid, cons_tid1, cons_tid2;
// initialize pthread variables
pthread_mutex_init(&mutex, NULL);
// initialize condition variables
pthread_cond_init(&cond1, NULL);
pthread_cond_init(&cond2, NULL);
// start producer thread
pthread_create(&prod_tid, NULL, producer, NULL);
// start consumer threads
pthread_create(&cons_tid1, NULL, consumer, NULL);
pthread_create(&cons_tid2, NULL, consumer, NULL);
// wait for threads to finish
pthread_join(prod_tid, NULL);
pthread_join(cons_tid1, NULL);
pthread_join(cons_tid2, NULL);
// clean up
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond1);
pthread_cond_destroy(&cond2);
return 0;
}
// producer thread executes this function
void * producer(void *arg)
{
char key;
printf("Enter text for producer to read and consumer to print, use Ctrl-C to exit.\n\n");
// this loop has the producer read data in from stdin and place the read data on the shared buffer
while (1)
{
// read input key
scanf("%c", &key);
pthread_mutex_lock(&mutex);
while (shared_count == NITEMS)
pthread_cond_wait(&cond1, &mutex);
// store key in shared buffer
shared_buffer[prod_index] = key;
// update shared count variable
shared_count++;
// update producer index
if (prod_index == (NITEMS - 1))
prod_index = 0;
else
prod_index++;
// release mutex lock
pthread_cond_signal(&cond2);
pthread_mutex_unlock(&mutex);
}
return NULL;
}
// consumer thread executes this function
void * consumer(void *arg)
{
char key;
long unsigned int id = (long unsigned int)pthread_self();
// this loop has the consumer get data from the shared buffer and print to stdout
while (1)
{
// this loop is used to poll the shared buffer to see if it is empty:
// -- if empty, unlock and loop again to keep polling
// -- if not empty, keep locked and proceed to get character from shared buffer
pthread_mutex_lock(&mutex);
while (shared_count == 0)
pthread_cond_wait(&cond2, &mutex);
// read key from shared buffer
key = shared_buffer[cons_index];
// echo key
printf("consumer %lu: %c\n", (long unsigned int) id, key);
// update shared count variable
shared_count--;
// update consumer index
if (cons_index == (NITEMS - 1))
cons_index = 0;
else
cons_index++;
pthread_cond_signal(&cond1);
// release mutex lock
pthread_mutex_unlock(&mutex);
}
return NULL;
}
评论
0赞
ikegami
10/28/2023
您在没有解释的情况下修复的一件事是,它可能会虚假唤醒,因此应始终在循环中使用。pthread_cond_wait
while ( !in_desired_state() ) pthread_cond_wait( &cond, &mutex );
0赞
David Schwartz
10/28/2023
@ikegami 这在代码中不是问题,因为它已经使用了测试谓词的循环,它只是以一种不寻常的方式这样做,具有过多的互斥锁/锁定周期。
评论