多个生产者和消费者使用3个sempahores

时间:2016-10-22 02:51:43

标签: c concurrency synchronization semaphore

使用大小为24的给定共享缓冲区

enter image description here

以下解决方案适用于单一生产者和消费者使用计数信号量,

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>

#define BUFFERSIZE 24

void *producer(void *);
void *consumer(void *);

sem_t mutex;          //Controls buffer access
sem_t fullBuffer;     //Prevents underflow
sem_t emptyBuffer;    // Prevents overflow

char buf[BUFFERSIZE] = {0}; //Shared resource

int main(int argc, char *argv[])
{
    pthread_t thread1, thread2;

    sem_init(&mutex, 0, 1);
    sem_init(&fullBuffer, 0, 0);
    sem_init(&emptyBuffer, 0, BUFFERSIZE);

    int ret1, ret2;

    ret1 = pthread_create(&thread1, NULL, producer, (void *)0);
    ret2 = pthread_create(&thread2, NULL, consumer, (void *)0);

    printf("Main function after pthread create\n");

    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);

    sem_destroy(&mutex);
    sem_destroy(&fullBuffer);
    sem_destroy(&emptyBuffer);

    return 0;
}

void *producer(void *index)
{
    int * startIndex = index;
    int currentProduceIndex = *startIndex;
    while(1) {
        sem_wait(&emptyBuffer); // Prevents overflow, when value is 0
        sem_wait(&mutex);       // Controls buffer access
        buf[currentProduceIndex] = currentProduceIndex;
        sem_post(&mutex);
        sem_post(&fullBuffer);
        currentProduceIndex = (currentProduceIndex+1) % BUFFERSIZE;
    }
}

void *consumer(void *index)
{
    int *startIndex = index;
    int currentConsumeIndex = *startIndex;
    while(1) {
        sem_wait(&fullBuffer); // Prevents underflow, when value is 0
        sem_wait(&mutex);
        printf("Consumed %d: ", buf[currentConsumeIndex]);
        sem_post(&mutex);
        sem_post(&emptyBuffer);
        currentConsumeIndex = (currentConsumeIndex+1) % BUFFERSIZE;
    }
}

上面的代码在buf上有单个生产者和消费者,使用3个信号量mutexfullBuffer&amp; emptyBuffer

要进一步添加,3信号量,mutexfullBuffer&amp; emptyBuffer足以让多个生产者和消费者在上面的代码中访问buf

1 个答案:

答案 0 :(得分:1)

正如seibie指出的那样,使用信号量很难实现。我修改了代码并使用了两个互斥锁和两个cond变量。您可以创建多个生产者和消费者线程,它应该可以正常工作。

#include <stdio.h>
#include <pthread.h>

#define BUFFERSIZE 24

void *producer(void *);
void *consumer(void *);

pthread_mutex_t consMutex;
pthread_mutex_t prodMutex;
pthread_cond_t  consCond;
pthread_cond_t  prodCond;

// Shared resource: Using it to store flags.
// If value at index is 0, it means the index is free
// and producer can write data. If it is 1, it means
// that index is filled, consumer can consume it.
// You need use separate array for actual data.
char buf[BUFFERSIZE] = {0};

int main(void)
{
   pthread_t thread1, thread2;

    pthread_mutex_init(&consMutex, NULL);
    pthread_mutex_init(&prodMutex, NULL);

    pthread_cond_init(&consCond, NULL);
    pthread_cond_init(&prodCond, NULL);

    int ret1, ret2;

    int prodIndex = 0;
    int consIndex = 0;

    ret1 = pthread_create(&thread1, NULL, producer, (void *)&prodIndex);
    ret2 = pthread_create(&thread2, NULL, consumer, (void *)&consIndex);

    printf("Main function after pthread create\n");

    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);

    pthread_mutex_destroy(&prodMutex);
    pthread_mutex_destroy(&consMutex);

    pthread_cond_destroy(&prodCond);
    pthread_cond_destroy(&consCond);

    return 0;
}

void *producer(void *index)
{
    int *currentProduceIndex = index;
    while(1) {
        pthread_mutex_lock(&prodMutex);

        /* Check if current index is free to fill. */
        while(1 == buf[*currentProduceIndex])
        {
            /* If index is not free, wait for consumer to consume. */
            pthread_cond_wait(&prodCond, &prodMutex);
        }

        /* Now the current index is free. Fill it. */
        buf[*currentProduceIndex] = 1;

        /* Update the producer index. */
        *currentProduceIndex = (*currentProduceIndex+1)%BUFFERSIZE;
        pthread_mutex_unlock(&prodMutex);

        /* Notify consumer that an item has been produced. */
        pthread_mutex_lock(&consMutex);
        pthread_cond_signal(&consCond);
        pthread_mutex_unlock(&consMutex);
    }

    return NULL;
}

void *consumer(void *index)
{
    int *currentConsumeIndex = index;
    while(1) {

        pthread_mutex_lock(&consMutex);

        /* Check if current index is empty. */
        while(0 == buf[*currentConsumeIndex])
        {
            /* If index is empty, wait for producer to produce. */
            pthread_cond_wait(&consCond, &consMutex);
        }

        /* Index is filled, consume it. */
        buf[*currentConsumeIndex] = 0;

        /* Update the consumer index. */
        *currentConsumeIndex = (*currentConsumeIndex+1)%BUFFERSIZE;
        pthread_mutex_unlock(&consMutex);

        /* Notify producer that an item has been consumed. */
        pthread_mutex_lock(&prodMutex);
        pthread_cond_signal(&prodCond);
        pthread_mutex_unlock(&prodMutex);
    }

    return NULL;
}