生产者 - 消费者使用pthreads的死锁

时间:2017-11-04 05:26:39

标签: c pthreads consumer producer

我正在使用pthread来解决生产者 - 消费者问题。基本上,生产者将文件读取到缓冲区,并且消费者(至少一个,但不限于)从缓冲区中获取条目并逐个操作它们。 这是制片人:

//...Local stuff...
if(file){
    while(fgets(line, 256, file)){            
        pthread_mutex_lock(&buffer_mutex);            
        while(data->buffer->buffer_items == data->buffer->buffer_size){               
            pthread_cond_wait(&buffer_full_cv, &buffer_mutex);}
        data->buffer->buffer_items);
        reads++;
        add_to_head(data->buffer, line);
        pthread_cond_broadcast(&buffer_ready_cv);            
        pthread_mutex_unlock(&buffer_mutex);            
    }
    pthread_mutex_lock(&buffer_mutex);
    work = 0;
    pthread_mutex_unlock(&buffer_mutex);
    fclose(file);
}

这就是消费者:

//...Local stuff...
while(1){
    pthread_mutex_lock(&buffer_mutex);        
    while(data->buffer->buffer_items == 0){
        if(work)
            pthread_cond_wait(&buffer_ready_cv, &buffer_mutex);            
        else if(!work && !data->buffer->buffer_items)
            pthread_exit(NULL);
    }
    remove_from_tail(data->buffer, string_to_check);
    data->buffer->buffer_items);
    pthread_cond_signal(&buffer_full_cv);
    pthread_mutex_unlock(&buffer_mutex);

    for(unsigned int i = 0; i < data->num_substrings; i++){    
        cur_occurrence = strstr(string_to_check, data->substrings[i]);
        while(cur_occurrence != NULL){
            pthread_mutex_lock(&buffer_mutex);
            data->occurrences[i]++;
            cur_occurrence++;
            cur_occurrence = strstr(cur_occurrence, data->substrings[i]);
            pthread_mutex_unlock(&buffer_mutex);
        }
    }
}

似乎正在发生的事情是文件被完全读取并且仍有工作要做,但由于生产者不再运行,消费者的等待永远不会完成。

  

PS:我也尝试过pthread_cond_signal而不是广播,但也没有用。

无论如何,这里有什么我想念的吗?

1 个答案:

答案 0 :(得分:1)

  

似乎正在发生的事情是文件被完全读取并且仍有工作要做,但由于生产者不再运行,消费者的等待永远不会完成。

从技术上讲,这不是僵局。这是生产者/消费者线程配置的常见挑战。有多种方法可以解决这个问题。

  • 您可以使用一个特殊的缓冲区值(与空缓冲区分开),它表示生产者已完成。 (如果你有多个消费者,这个特殊值必须留在缓冲区中。)这种带内信令虽然有时很方便实现,但通常不是一个好的设计。
  • 如果你有多个生成器,你可能应该将缓冲区与运行的生成器数量的计数器结合起来,实质上是向缓冲区添加一个信号量。如果生产者的数量达到零,则消费者需要退出。
  • 产生生产者和消费者的线程可以在加入所有消费者后使用pthread_cancel,以便pthread_cond_wait中止。但是,要想完全正确,这一点很棘手,一般来说,最好避免取消。

请注意,如果您有多个消费者,每个消费者都需要在观察到已达到数据结束状态后广播该信号,以便其他消费者也有机会观察它,