同步1个生产者和1个以上的消费者(多线程)

时间:2012-08-31 14:46:27

标签: c++ linux multithreading

我想实现生产者 - 消费者场景,其中有一个生产者线程和多个消费者线程。 实际上,具体来说,生产者线程需要定期创建一组对象(例如,5秒),并且消费者线程需要使用对象。

我不确定如何定期创建一组对象以及如何同步多个消费者。

提前致谢

3 个答案:

答案 0 :(得分:2)

你究竟遇到了什么问题?传统上,工作队列受条件锁保护;如果多个“消费者”正在等待同一个锁,那么其中只有一个会成功获得它。但是,您应该从中获取一个对象,将其从队列中删除,然后在处理作业之前释放锁定,而不是抓取整个队列。

至于定期创建作业,这是您正在使用的任何库中的计时器类的工作。如果您正在等待输入,则select()和poll()调用具有超时值;如果你没有做任何事情,你可以打电话给[u] sleep()。

答案 1 :(得分:1)

我不会拼出所有代码,但您可以为此使用互斥锁和条件变量(以及链接列表)。基本模式是生产者做的:

loop_forever
    wait_until_interval_has_elapsed
    lock_the_mutex
        append_an_item_to_the_list
        signal_the_condvar // can be outside the mutex
    unlock_the_mutex

每个消费者都这样做:

loop_forever
    lock_the_mutex
        while(list_is_empty)
            wait_the_condvar
        remove_an_item_from_the_list
    unlock_the_mutex
    process_the_item

您也可以使用互斥锁和信号量:

loop_forever
    wait_until_interval_has_elapsed
    lock_the_mutex
        append_an_item_to_the_list
    unlock_the_mutex
    post_the_semaphore

loop_forever
    wait_the_semaphore
    lock_the_mutex
        remove_an_item_from_the_list
    unlock_the_mutex
    process_the_item

这稍微简单,但是一旦你决定添加一种机制来告诉消费者完成他们正在做的事情并退出你可能会更好地使用条件变量,因为你可以“广播”它。信号量因易误用而略有声誉,这就是C ++ 11没有信号量的原因。但是,Posix确实在Linux上有你的选择。并且公平地说,大致所有其他多线程操作系统也是如此。

在线程具有不同优先级的情况下,互斥/ condvar对也可能比信号量提供更好的行为。与互斥锁不同,信号量没有“所有者”,因此优先级继承等技术是不可能的。

对于wait_until_interval_has_elapsed使用计时器或睡眠功能 - 请注意,除非您使用的是实时系统,否则您永远无法确定您是否能够在特定时间运行,只有您能够在特定时间或之后被唤醒。

答案 2 :(得分:1)

您需要一种方法来告诉消费者线程有新对象可用。这是一个例子(我没有包含#include):

#define NUM_CONSUMERS 2

static int objects[4]; //The place for produced objects
static pthread_mutex_t cond_mut = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

void* producer_func(void* arg);
void* consumer_func(void* arg);

int main(int argc, char** argv) {
  pthread_t producer;
  pthread_t consumers[NUM_CONSUMERS];
  int res;
  void* zero = 0;
  res = pthread_create(&producer, NULL, producer_func, zero); 
  for(int i = 0; i < NUM_CONSUMERS; i++) {
    res = pthread_create(&consumers[i], NULL, consumer_func, zero);
  }
}

void* producer(void* arg) {
  while(1) {
    objects[0] = 0;
    objects[1] = 1;
    objects[2] = 2;
    objects[3] = 3;
    pthread_mutex_lock(&cond_mut);
    pthread_cond_signal(&cond);
    pthread_mutex_unlock(&cond_mut);
    sleep(5);
  }
}

void* consumer(void* arg) {
  while(1) {
    pthread_mutex_lock(&cond_mut);
    pthread_cond_wait(&cond);
    pthread_mutex_unlock(&cond_mut);
    //Process objects here 
  }
}