一个消费者和一个两个生产者

时间:2015-03-24 18:19:24

标签: c multithreading semaphore producer-consumer

我在编写这个C代码时遇到问题,我需要让两个生产者拥有自己的缓冲区。然后一个消费者从任一缓冲区消耗一个项目,只在两个缓冲区都为空时才等待。我知道如果消费者等待生成器缓冲区为空,

,如何编写代码
sem_wait(Xfull);
item1 = BufferX[outX];
sem_signal(Xempty);

sem_wait(Yfull);
item2 = BufferB[outY];
sem_signal(BufferBEmpty);

但我坚持这个。

3 个答案:

答案 0 :(得分:1)

您可以拥有一个信号量来计算两个队列中未消耗项目的总数。生产者发布信息,消费者等待它。一旦消费者成功等待信号量,它就会使用互斥量检查每个队列以找到要使用的项目。

sem_t ProducedItems;  // counts total # of unconsumed items in Q's A and B
sem_t Q_A;            // mutex on Q A
sem_t Q_B;            // mutex on Q B

void *consumer(void *arg)
{
  int bias = 0;  // NOTE: could use to not always favor reading from Q A over Q B

  while (1)
  {
    // wait for an item to be produced
    sem_wait(&ProducedItems);

    // find an item to consume
    do 
    {
      sem_wait(&Q_A);
      {
        if (Q A not empty) 
        {
          remove an item from Q A;
          bias = 1;
        }
      }
      sem_post(&Q_A);

      if (got item from A)
        break;

      sem_wait(&Q_B);
      {
        remove an item from Q B;
        bias = 0;
      }
      sem_post(&Q_B);
    } 
    while (0);

    // consume item
  }

  return NULL;
}

如果消费者还需要向生产者发出信号,例如确保他们的Q不会变得太大,那么你也可以为每个制作人提供信号量,表明他们留下了多少空间。他们的问答。生产者会等待其信号量,消费者会在他们从各自的Q中删除项目时向其发帖。

如果您想将此概括为N制作Q,那么您可能希望保留一个由互斥锁保护的掩码,指示哪些Q在其上有未消耗的项目。

一旦消费者获得了ProducedItems信号量,那么它将锁定掩码以查看哪些Q在其上有未消耗的项目并对它们进行循环进展以决定下一个应该从哪个Q读取。然后它会锁定+从该Q中获取一个项目,如果该Q变空则更新位掩码,释放互斥锁并最终使用该项目。

生产者会将项目放入他们的Q中,如果它已经是空的,那么他们也会锁定全局位掩码并将其Q位置于那里,释放互斥锁然后发布ProducedItems信号量。 / p>

或者不是有点掩码,你可以有一个Q的大小数组,虽然这需要生产者在每次产生时锁定互斥锁等。

答案 1 :(得分:0)

一个选项是在两个信号量中实现忙等待:

int sem;
do {
    if (sem_trywait(sem1) == 0) {
        sem = 1;
        break;
    }
    if (sem_trywait(sem2) == 0) {
        sem = 2;
        break;
    }

    usleep(1);
} while (1);

if (sem == 1) {
    ...
}

我在this回答中找到的另一个选项是查看sun WaitForMultipleObjects api的实现,并引用:

  

基本思想是将条件变量列表与a相关联   句柄(由互斥锁保护),并发出所有条件信号   每当句柄发出信号时变量。每次你打电话给   模拟WaitForMultipleObjects,创建一个新的条件变量   并添加到您感兴趣的所有句柄列表中   WaitForMultipleObjects仿真,你阻塞条件变量,   醒来后检查每个把手。

可以找到论文here

答案 2 :(得分:0)

在这种情况下,

条件变量适用。

如果我理解你的问题。你有一个消费者要消费两个生产者。因此,你可以

pthread_cond_t *cond;
pthread_mutex_t *cond_mutex;
sem_t *x, *y;

在消费者中:

while(exit_cond) {
    pthread_cond_wait(cond, cond_mutex);
    if(sem_trywait(x) == 0)
        consumeX(); // then post x
    if(sem_trywait(y) == 0)
        consumeY(); // then post y
}

在两个制作人中:

while(exit_cond) {
    produce(); //  hold and release semaphore
    pthread_cond_signal(cond);
}
通过这种方式,所有消费者和生产者都可以尽可能平行工作。