Linux pthread生产者和消费者

时间:2015-05-19 22:06:34

标签: c multithreading concurrency pthreads producer-consumer

为了学术目的,我必须编写基于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

是否存在导致这些总和不相等的逻辑或实现错误?

1 个答案:

答案 0 :(得分:0)

生产者

不正确

考虑你的制作人:

'all'

让我们假设发生以下序列:

  1. 制作人#1一直运行到上面的评论然后停止。假设其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写入任何内容。
  2. 现在,生产者#2贯穿整个代码。它的write_index为1,将其ID写入buffer[0],然后发布到my_write_index
  3. 接下来,消费者#1获得buffer[1],因为它是由生产者#2发布的。它尝试使用一个元素,但下一个consumer_semaphore为0.不幸的是,consumer_semaphore尚未由生产者#1写入,并且具有之前留下的任何未知值。
  4. 要修复代码,您需要修改生产者以在释放互斥锁之前写入缓冲区。换句话说,切换这两行的顺序:

    read_index
相关问题