我使用大小为 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/