使用条件变量

时间:2015-08-03 05:14:26

标签: c++ list pthreads producer-consumer

我使用C ++ list作为缓冲区,用pthreads和条件变量编写单个生成器多个使用者缓冲区的简单实现。我并不太担心代码的运行速度,我只是想摆脱错误。

生产者线程从文件中读取字符串并将其插入缓冲区的末尾,而消费者中的每一个从头开始读取并将其放在不同的矩阵。所以,essencialy,我有一个FIFO队列,它有一个最大大小,第一个元素只能在所有消费者都已阅读时删除。

这是我的代码的三个功能的重要部分:

PRODUCER:

void *feedBuffer(void *threadproducer){
//some declarations...
while(!file->eof())
{   
    pthread_mutex_lock(&mutex);

    while(*buffer_current_size == buffer_max_size) { // full
        // wait until some elements are consumed
        pthread_cond_wait(&can_produce, &mutex);
    }

    pthread_mutex_lock(&lock_buffer); 
        *file >> temp.word;
        buffer->push_back(temp);
        (*buffer_current_size)++;
    pthread_mutex_unlock(&lock_buffer);

    pthread_cond_broadcast(&can_consume);
    pthread_mutex_unlock(&mutex);
}
file->close();
pthread_cond_broadcast(&can_consume);

pthread_mutex_lock(&lock_buffer);
    buffer_current_size->store(-1); //END OF READ SIGNAL
pthread_mutex_unlock(&lock_buffer);
pthread_exit(NULL);
}

BUFFER控制器和工人线程CALLER:

void *main_consumer(void *threadconsumer) //consumer caller and buffer controll
{  
//some declarations...
for(int j=0; j<NUMTHREADS; j++)
{  
    pthread_create(&threads[j],&attr,worker,(void *) &workerargs[j]);
}

//BUFFER CONTROLLER
pthread_mutex_lock(&lock_buffer);

while(*buffer_current_size!=-1){ //WHILE READ HASN'T ENDED

    pthread_mutex_unlock(&lock_buffer); //UNLOCK AND LOCK AGAIN TO LET OTHER THREADS HOLD THE LOCK FOR A WHILE
    pthread_mutex_lock(&lock_buffer);

    it=buffer->begin(); //GET FIRST ELEMENT OF THE BUFFER
    if(it->cnt == NUMTHREADS){
        buffer->pop_front(); //DELETE FIRST ELEMENT
        (*buffer_current_size)--; //DECREASE SIZE

        pthread_cond_signal(&can_produce); //PRODUCER CAN PRODUCE
    }
}
pthread_mutex_unlock(&lock_buffer);
for(int i=0; i<NUMTHREADS; i++)
{
    pthread_join(threads[i],NULL);
}
}

工人:

void *worker(void *threadwoker)
{
//some declarations...
pthread_mutex_lock(&lock_buffer); //LOCK TO GET BEGIN
it=buffer->begin();
while(!(*buffer_current_size==-1 && it==args->buffer->end())) {
    pthread_mutex_unlock(&lock_buffer);
    //insert into matrix...

    pthread_mutex_lock(&lock_buffer); //UNIFIED LOCK FOR IT AND CNT, SOLVING ISSUE
        (it->cnt)++;
        it++;
    pthread_mutex_unlock(&lock_buffer);

    pthread_mutex_lock(&mutex);
    while (*buffer_current_size==0) { //WAIT IF BUFFER EMPTY

        pthread_cond_wait(&can_consume, &mutex);
    }
    pthread_mutex_unlock(&mutex);


    pthread_mutex_lock(&lock_buffer); //LOCKING FOR WHILE ARGUMENTS
}
pthread_mutex_unlock(&lock_buffer);
pthread_exit(NULL);
}

正如您所看到的,我在缓冲区的每个元素上使用了一个int计数器来检查所有工作线程是否已经读取它。当此条件成立时,缓冲区控制器将从队列中删除第一个元素。所有都是锁定,以保证数据的完整性。

问题是,这段代码不起作用,我得到段错误或互斥错误。任何人都可以启发任何想法吗?

1 个答案:

答案 0 :(得分:1)

首先,不清楚每个互斥锁正在保护哪些数据结构。我建议至少在初始实现时,简化为保护所有共享状态的一个互斥锁 - 即缓冲区大小计数器,缓冲区本身和工作项中的计数器。

至于具体问题:

  • 生产者应该在pthread_cond_wait()之后重新测试条件(它应该是while ()循环而不是if ()语句);
  • 当制作人完成时,它会在没有锁定的情况下访问*buffer_current_size并且不会向任何等待的消费者发出信号;
  • 缓冲区控制器在没有锁定的情况下访问*buffer_current_size;
  • 工作人员在没有锁定的情况下访问buffer->begin()buffer->end();
  • 工人在没有锁定的情况下访问*buffer_current_size;
  • 工作人员在不检查结果的情况下调用pthread_mutex_trylock(&mutex),这意味着它可以访问共享状态并在不锁定互斥锁的情况下解锁互斥锁;
  • 工人需要在致电pthread_cond_wait()后重新检查其等待的情况;
  • 工作者在没有锁定的情况下访问迭代器it,这是有问题的,因为其他线程修改了底层::list - 因为这个线程已经增加了计数器,缓冲区控制器可能已经被删除迭代器指向的项,这意味着你不能递增迭代器。