我正在使用ubuntu 16.04在具有2个处理器的虚拟机上使用pthread来实现消费者 - 生产者问题。我们有n个生产者和一个消费者,他们通过缓冲区从每个生产者那里读取数据。每个生产者都有自己的缓冲区。问题是,在某些时候我的代码死锁,无法找出原因。可能是我搞乱了条件变量和互斥锁。
typedef struct
{
Student* buf; // the buffer
int producer_id;
size_t len; // number of items in the buffer
pthread_mutex_t mutex; // needed to add/remove data from the buffer
pthread_cond_t can_produce; // signaled when items are removed
pthread_cond_t can_consume; // signaled when items are added
bool isDone;
} buffer_t;
这是消费者和生产者之间数据传输的缓冲结构。
void* producer(void *param)
{
buffer_t* buffer = (buffer_t*)param;
char* line = NULL;
size_t len = 0;
ssize_t read;
FILE* inFileReader;
inFileReader = fopen(inFile, "r");
while ((read = getline(&line, &len, inFileReader)) != -1)
{
pthread_mutex_lock(&buffer->mutex);
if (buffer->len == BUFFER_SIZE)
{// buffer full wait
pthread_cond_wait(&buffer->can_produce, &buffer->mutex);
}
//buffer filled up with the read data from the file.
if (conditionValid)
{
//add item to buffer
++buffer->len;
}
pthread_cond_signal(&buffer->can_consume);
pthread_mutex_unlock(&buffer->mutex);
}
fclose(inFileReader);
buffer->isDone = true;
pthread_exit(NULL);
return NULL;
}
这是生产者,从给定的文件中读取数据并填充缓冲区,当文件结束时,生产者线程将退出。
void* consumer(void *param)
{
buffer_t* buffer_array = (buffer_t*)param;
sleep(rand() % 3);
int i =0;
while (!buffer_array[i%N].isDone || buffer_array[i%N].len != 0)
{
pthread_mutex_lock(&buffer_array[i%N].mutex);
if (buffer_array[i%N].len == 0)
{
pthread_cond_wait(&buffer_array[i%N].can_consume,
&buffer_array[i%N].mutex);
}
while (buffer_array[i%N].len != 0)
{
buffer_array[i%N].len--;
//read from buffer
}
pthread_cond_signal(&buffer_array[i%N].can_produce);
pthread_mutex_unlock(&buffer_array[i%N].mutex);
i++;
}
fclose(outFileWriter);
pthread_exit(NULL);
return NULL;
}
消费者从每个生产者那里读取缓冲区,当所有完成的消费者退出循环并终止线程时。
任何帮助表示感谢。
答案 0 :(得分:0)
死锁是因为生产者只用一个标志集完成阅读:
buffer->isDone = true;
所以,如果那时消费者正在等待生产者1的条件:
// say i == 1
if (buffer_array[i%N].len == 0)
{
pthread_cond_wait(&buffer_array[i%N].can_consume,
&buffer_array[i%N].mutex);
}
这种情况永远不会发生。消费者没有进步,所以一切都只是摊位。
解决方案可能是在设置isDone后触发can_consume
。