c - 生产者-消费者堆栈行为而不是队列

标签 c producer-consumer

我使用大小为 5 的缓冲区和带有空信号量和满信号量和互斥锁的 pthreads 编写了标准生产者-消费者问题的解决方案。我以为一切都按预期工作,但只是注意到我得到的是堆栈行为(后进先出)而不是预期的队列(先进先出)行为。我搜索过但没有发现任何类似的问题,因为我正在按预期生产和消费,而不是订单。

这是一项家庭作业,所以我并不是真的在寻找代码,我只是想知道在哪里寻找错误或知道行为可能与预期不同的原因。

struct data
{
pthread_mutex_t mutex;  
sem_t full;             
sem_t empty;
};

int bufferCount;        

buffer_item buffer[BUFFER_SIZE];
pthread_t thread;

int insert_item(buffer_item item)
{
  if (bufferCount < BUFFER_SIZE)
  {
    buffer[bufferCount] = item;
    ++bufferCount;
    return 0;
  }
  else
    return -1; //insert failed 
}

int remove_item(buffer_item *item)
{
  if (bufferCount > 0) 
  {
    *item = buffer[bufferCount - 1];
    --bufferCount;
    return 0;
  }
  else
    return -1; //error failed to remove

}

void Initialize (void *param)
{
  struct data *locks = param;

  pthread_mutex_init(&(locks->mutex), NULL);
  sem_init(&(locks->full), 0, 0);
  sem_init(&(locks->empty), 0, BUFFER_SIZE);
  bufferCount = 0;

}

void *producer (void *param)
{
  struct data *locks = param;
  do
  {
    sleep(rand()%5 + 1); //sleep for between 1 and 5 seconds
    buffer_item num = rand();
    sem_wait(&(locks->empty));
    pthread_mutex_lock(&(locks->mutex));
    if (insert_item(num))
    {
      printf("Insert in producer failed\n");
      exit(1);
    }
    else
      printf("Producer produced %d\n", num);
    pthread_mutex_unlock(&(locks->mutex));
    sem_post(&(locks->full));
  }while(1);
}


void *consumer (void *param)
{
  struct data *locks = param;
  do
  {
    sleep(rand()%5 + 1); //sleep for between 1 and 5 seconds
    buffer_item num;
    sem_wait(&(locks->full));
    pthread_mutex_lock(&(locks->mutex));
    if (remove_item(&num))
    {
      printf("Remove in consumer failed\n");
      exit(1);
    }
    else
      printf("Consumer consumed %d\n", num);
    pthread_mutex_unlock(&(locks->mutex));
    sem_post(&(locks->empty));
  }while(1);
}


int main(int argc, char *argv[])
{
  if (argc != 4)
  {
    printf("Incorrect number of arguments should be 4\n");
    exit (1);
  }
  int sleepTime = atoi(argv[1]);  
  int producerThreads = atoi(argv[2]);
  int consumerThreads = atoi(argv[3]);
  struct data *locks = (struct data *) malloc(sizeof(struct data));
  Initialize(locks);

  for (int i =0; i < producerThreads; ++i)
    pthread_create(&thread, NULL, producer, locks);

  for(int i = 0; i < consumerThreads; ++i)
    pthread_create(&thread, NULL, consumer, locks);

  sleep(sleepTime); 
  free (locks);
  return 0;
}

最佳答案

你的“错误”在这里:*item = buffer[bufferCount - 1];

当你删除一个项目时,你弹出了数组中最远的,这也是最后插入的(因此是后进先出的行为)。您需要弹出第一个(和 memcpy/index-keeping 以移动缓冲区的开头)。

你做什么:

begin         <-end  
-------------------
| | | | | | | | |x|
-------------------
                 |
                 -> *item

你想做什么:

begin->         end  
-------------------
|x| | | | | | | | |
-------------------
 |
 -> *item

PS:memcpy 缓冲区重新对齐数据数组的开头存在性能损失,这就是为什么 circular buffers经常使用。

关于c - 生产者-消费者堆栈行为而不是队列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22501915/

相关文章:

c - 为什么局部变量可以作为函数的返回值?

c - 使用 iconv 进行简单的 UTF8->UTF16 字符串转换

c++ - typedef 只是代码中的字符串替换还是其他内容?

C : Memory Layout of c program and Endianess

c - 单链表最后一个节点指向列表中的任意节点

multithreading - 消费者和生产者之间的Qt线程释放? Qmutex? Q信号量?什么?

c - 生产者消费者同步使用两个线程提供不正常的串行输出

java - 在这些线程中,这个 boolean 值是做什么用的?

c# - 如何分块化 IEnumerable<T>,而不会在失败时丢失/丢弃项目?

c# - 在 ConcurrentQueue 中尝试出队