微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

是否可以使用条件变量和信号而不是广播来创建生产者消费者问题? 更新

如何解决是否可以使用条件变量和信号而不是广播来创建生产者消费者问题? 更新

我试图在使用pthread_cond_signal()而不是pthread_cond_broadcast()时运行生产者-消费者问题,但是,我尝试了很多事情,但似乎无法做到(如果我选择{{ 1}} 生产者和 n 消费者然后消费者完成但并非所有生产者都完成,有些人卡在完整队列中,因此问题永远不会完成执行。我从其他人的 GitHub 上获得了 initial code,我正在尝试编辑它来完成(你可以查看附加链接上的代码,我会粘贴在帖子的末尾)。这里的相关部分是生产者和消费者功能,目前我有以下内容

消费者:

one

制作人:

void *consumer (void *carg)
{
  queue  *fifo;
  int     item_consumed;
  pcdata *mydata;
  int     my_tid;
  int    *total_consumed;

  mydata = (pcdata *) carg;

  fifo           = mydata->q;
  total_consumed = mydata->count;
  my_tid         = mydata->tid;

  while (1) {
     pthread_mutex_lock(fifo->mutex); //start of the critical section
 
    while (fifo->empty && *total_consumed != WORK_MAX) {
      printf ("con %d:   EMPTY.\n",my_tid);
      pthread_cond_wait(fifo->notEmpty,fifo->mutex); //if queue is empty then wait for signal that it has something to start consuming
    }

 
    if (*total_consumed >= WORK_MAX) {
       pthread_mutex_unlock(fifo->mutex); //if max work is reached then unlock the mutex and exit
      break;
    }
    queueRemove (fifo,&item_consumed); //reaching this means that queue isn\t empty so just consume
    (*total_consumed)++;
    do_work(CONSUMER_cpu,CONSUMER_cpu);

    printf ("con %d:   %d.\n",my_tid,item_consumed);

    pthread_cond_signal(fifo->notFull); //consumption is done so queue isn't full,signal to producer
    pthread_mutex_unlock(fifo->mutex);
  }

  printf("con %d:   exited\n",my_tid);
  return (NULL);
}

我的问题是并非所有线程都收到退出信号,例如运行多达 13 个生产者和一个消费者工作但超过 13 个生产者和一个消费者的所有东西都卡住了,这是运行 14 个生产者和一个消费者的执行示例消费者:

void *producer (void *parg)
{
  queue  *fifo;
  int     item_produced;
  pcdata *mydata;
  int     my_tid;
  int    *total_produced;

  mydata = (pcdata *) parg;

  fifo           = mydata->q;
  total_produced = mydata->count;
  my_tid         = mydata->tid;

  while (1) {
      
    pthread_mutex_lock(fifo->mutex);
    do_work(PRODUCER_cpu,PRODUCER_BLOCK);
 
  
    while (fifo->full && *total_produced != WORK_MAX) {
      printf ("prod %d:  FULL.\n",my_tid);
      pthread_cond_wait(fifo->notFull,fifo->mutex); //if queue is full then wait for signal that is not anyone to start producing
  
    }

    if (*total_produced >= WORK_MAX) {
      pthread_mutex_unlock(fifo->mutex); //if total work reached then exit
      break;
    }

    item_produced = (*total_produced)++;
    queueAdd (fifo,item_produced);


    printf("prod %d:  %d.\n",item_produced);
    pthread_cond_signal(fifo->notEmpty); //reaching this means we produced something so signal that queue is not empty
    pthread_mutex_unlock(fifo->mutex);
  }

  printf("prod %d:  exited\n",my_tid);
  return (NULL);
}

任何帮助将不胜感激。

如果有人感兴趣,请提供完整代码(它很长,但我想大多数相关部分已经在我发布的方法中):

con 0:   EMPTY.
prod 3:  2.
prod 9:  FULL.
prod 11:  FULL.
prod 13:  FULL.
prod 0:  0.
prod 8:  3.
prod 6:  1.
prod 12:  FULL.
prod 7:  4.
prod 10:  FULL.
prod 1:  FULL.
prod 2:  FULL.
prod 5:  FULL.
prod 4:  FULL.
prod 9:  5.
prod 3:  FULL.
prod 0:  FULL.
prod 6:  FULL.
prod 8:  FULL.
prod 7:  FULL.
prod 9:  FULL.
con 0:   0.
prod 11:  6.
prod 13:  FULL.
prod 11:  FULL.
con 0:   1.
prod 12:  7.
prod 10:  FULL.
prod 12:  FULL.
con 0:   2.
prod 1:  8.
prod 2:  FULL.
prod 1:  FULL.
con 0:   3.
prod 4:  9.
prod 5:  FULL.
prod 4:  FULL.
con 0:   4.
prod 3:  10.
prod 0:  FULL.
prod 3:  FULL.
con 0:   5.
prod 6:  11.
prod 8:  FULL.
prod 6:  FULL.
con 0:   6.
prod 7:  12.
prod 9:  FULL.
prod 7:  FULL.
con 0:   7.
prod 13:  13.
prod 11:  FULL.
prod 13:  FULL.
con 0:   8.
prod 12:  14.
prod 10:  FULL.
prod 12:  FULL.
con 0:   9.
prod 2:  15.
prod 1:  FULL.
prod 2:  FULL.
con 0:   10.
prod 5:  16.
prod 4:  FULL.
prod 5:  FULL.
con 0:   11.
prod 3:  17.
prod 0:  FULL.
prod 3:  FULL.
con 0:   12.
prod 8:  18.
prod 6:  FULL.
prod 8:  FULL.
con 0:   13.
prod 9:  19.
prod 7:  FULL.
prod 9:  FULL.
con 0:   14.
prod 11:  20.
prod 13:  FULL.
prod 11:  FULL.
con 0:   15.
prod 10:  21.
prod 12:  FULL.
prod 10:  FULL.
con 0:   16.
prod 2:  22.
prod 1:  FULL.
prod 2:  FULL.
con 0:   17.
prod 4:  23.
prod 5:  FULL.
prod 4:  FULL.
con 0:   18.
prod 0:  24.
prod 3:  FULL.
prod 0:  FULL.
con 0:   19.
prod 6:  25.
prod 8:  FULL.
prod 6:  FULL.
con 0:   20.
prod 7:  26.
prod 9:  FULL.
prod 7:  FULL.
con 0:   21.
prod 11:  27.
prod 13:  FULL.
prod 11:  FULL.
con 0:   22.
prod 12:  28.
prod 10:  FULL.
prod 12:  FULL.
con 0:   23.
prod 1:  29.
prod 2:  exited
prod 1:  exited
con 0:   24.
prod 4:  exited
prod 5:  exited
con 0:   25.
prod 3:  exited
prod 0:  exited
con 0:   26.
prod 8:  exited
prod 6:  exited
con 0:   27.
prod 9:  exited
prod 7:  exited
con 0:   28.
prod 13:  exited
prod 11:  exited
con 0:   29.
con 0:   exited
prod 10:  exited

解决方法

我正在尝试解决生产者-消费者问题 使用 pthread_cond_signal() 而不是 pthread_cond_broadcast(), 然而,我尝试了很多事情,但似乎无法做到(如果我 选择 n 个生产者和一个消费者然后消费者完成但不 所有生产者都完成了,有些人被卡在了完整的队列中,所以问题是 永远不会完成执行。

嗯,这听起来很有道理。如果您在一个 CV 上阻塞了多个线程,那么一个信号将唤醒其中一个。其余的将保持阻塞状态。

我通常倾向于走另一条路。如果你正确使用你的简历,那么总是向它广播而不是向它发送信号是安全的,但相反的做法会暴露更多可能存在的错误,尤其是当涉及两个以上的线程时。

特别是对于关机场景,我建议只使用广播。您可能需要唤醒多个线程,而这正是 pthread_cond_broadcast() 的用途。如果您愿意,您可以让主线程来代替消费者或生产者。但是,如果您坚持只使用 pthread_cond_signal(),那么您必须确保调用该函数的次数足够多,以唤醒可能在 CV 上阻塞的所有线程。同样,这些调用中的一些或全部可以由主线程执行。

更新

尽管我上面建议广播,但一个相对好的方法是让每个生产者在终止前向 notFull CV 发出信号。你可以把它放在几个地方,但我自己可能会这样做:

    if (*total_produced >= WORK_MAX) {
      pthread_mutex_unlock(fifo->mutex); //if total work reached then exit
      pthread_cond_signal(fifo->notFull); // other producers should wake up and exit,too
      break;
    }

请注意,互斥锁当前不需要被发送广播或信号的线程锁定。

还要注意,如果你走这条路,那么消费者想要类似的待遇。

最后,请注意,对于此特定代码,您尝试执行的转换从功能角度来看是一个坏主意,尤其是对于生产者和消费者数量不同的情况。无论您开始使用多少个,它都会趋向于拥有相同数量的活跃​​生产者和消费者,并且可能在更长的时间范围内,在任何给定时间最多只有一个。这些后果源于多个消费者或多个生产者同时在 CV 上被阻止的情况。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。