为了学术目的,我必须编写基于POSIX线程和信号量的生产者和消费者问题的实现。为了检查实施是否有效,我总结了生产的所有“商品”和所有消费品。问题是,随后的计划执行之间的第二笔金额不同,并不总是等于生产的货物数量。我使用固定大小的循环缓冲区来保存生成的值,2个信号量用于让生产者和消费者进入关键部分,2个互斥量用于访问生产者和消费者的索引。 这是我的代码:
#include<unistd.h>
#include<pthread.h>
#include<semaphore.h>
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<time.h>
#define PRODUCERS_COUNT 10
#define CONSUMERS_COUNT 5
#define BUFFER_SIZE 2
#define ITERATIONS 1000
int buffer[BUFFER_SIZE];
pthread_mutex_t write_index_mutex;
pthread_mutex_t read_index_mutex;
sem_t producer_semaphore;
sem_t consumer_semaphore;
int write_index = 0;
int read_index = 0;
int total_produced_sum = 0;
int total_consumed_sum = 0;
void* producer_thread(void* args)
{
int producer_id = *((int*)args);
free(args);
int my_write_index;
int iterations = ITERATIONS;
while(iterations--)
{
sem_wait(&producer_semaphore);
pthread_mutex_lock(&write_index_mutex);
my_write_index = write_index;
write_index = (write_index + 1) % BUFFER_SIZE;
total_produced_sum += producer_id;
pthread_mutex_unlock(&write_index_mutex);
buffer[my_write_index] = producer_id;
sem_post(&consumer_semaphore);
usleep((rand() % 10));
}
return NULL;
}
void* consumer_thread(void* args)
{
int my_read_index;
while(1)
{
sem_wait(&consumer_semaphore);
pthread_mutex_lock(&read_index_mutex);
my_read_index = read_index;
read_index = (read_index + 1) % BUFFER_SIZE;
total_consumed_sum += buffer[my_read_index];
pthread_mutex_unlock(&read_index_mutex);
sem_post(&producer_semaphore);
usleep((rand() % 10));
}
return NULL;
}
int main()
{
int i;
int *id;
pthread_t producers[PRODUCERS_COUNT];
pthread_t consumers[CONSUMERS_COUNT];
sem_init(&producer_semaphore, 0, BUFFER_SIZE);
sem_init(&consumer_semaphore, 0, 0);
pthread_mutex_init(&write_index_mutex, NULL);
pthread_mutex_init(&read_index_mutex, NULL);
for(i = 0 ; i < PRODUCERS_COUNT ; i++)
{
id = (int*)malloc(sizeof(int));
*id = i+1;
pthread_create(&producers[i], 0, producer_thread, (void*)id);
}
for(i = 0; i < CONSUMERS_COUNT; i++)
{
pthread_create(&consumers[i], 0, consumer_thread, NULL);
}
for(i = 0; i < PRODUCERS_COUNT; i++)
{
pthread_join(producers[i], NULL);
}
while(1)
{
sem_getvalue(&consumer_semaphore, &i);
if(i == 0)
break;
}
printf("Goods produced: %d goods consumed: %d\n", total_produced_sum, total_consumed_sum);
return 0;
}
以下是同一程序10次运行的一些示例输出,没有重新编译:
Goods produced: 55000 goods consumed: 54996
Goods produced: 55000 goods consumed: 55000
Goods produced: 55000 goods consumed: 54998
Goods produced: 55000 goods consumed: 55003
Goods produced: 55000 goods consumed: 54998
Goods produced: 55000 goods consumed: 55000
Goods produced: 55000 goods consumed: 55008
Goods produced: 55000 goods consumed: 54999
Goods produced: 55000 goods consumed: 55000
Goods produced: 55000 goods consumed: 55000
Goods produced: 55000 goods consumed: 55000
是否存在导致这些总和不相等的逻辑或实现错误?
答案 0 :(得分:0)
考虑你的制作人:
'all'
让我们假设发生以下序列:
invalid
为0.它已将 sem_wait(&producer_semaphore);
pthread_mutex_lock(&write_index_mutex);
my_write_index = write_index;
write_index = (write_index + 1) % BUFFER_SIZE;
total_produced_sum += producer_id;
pthread_mutex_unlock(&write_index_mutex);
// Producer #1 stops right here.
buffer[my_write_index] = producer_id;
sem_post(&consumer_semaphore);
增加到1,但尚未向my_write_index
写入任何内容。write_index
为1,将其ID写入buffer[0]
,然后发布到my_write_index
。buffer[1]
,因为它是由生产者#2发布的。它尝试使用一个元素,但下一个consumer_semaphore
为0.不幸的是,consumer_semaphore
尚未由生产者#1写入,并且具有之前留下的任何未知值。要修复代码,您需要修改生产者以在释放互斥锁之前写入缓冲区。换句话说,切换这两行的顺序:
read_index