具有信号量,多个pthreads,2个缓冲区的生产者和消费者

时间:2014-02-25 15:39:01

标签: c multithreading concurrency producer-consumer

行。所以我有2个缓冲区,实现为堆。它具有init,insert和delete功能。在这种情况下,优先级无关紧要。

对于每个缓冲区,有3个生产者线程生成一个项目(字母)并将其插入缓冲区。三个生成器用于缓冲区,用于保存大写字母,三个用于缓冲区,用于保存小写字母。显然,只有1个生产者可以一次附加到缓冲区。

有10个消费者线程。这些线程可以访问任一缓冲区,但每个缓冲区一次最多只能访问3个,而不是生产者生产时。我试图指示线程首先进入缓冲区,其中包含更多项目,然后是另一个。

我的问题是我相信死锁。我得到分段错误,所以我假设我的信号量不能正常工作(我没有正确实现它们)。

我首先使用单个缓冲区解决了这个问题,有多个使用者/生产者,并且能够让它工作。我基本上将1缓冲区解析为多个部分。

我为每个缓冲区使用3个信号量。一个互斥锁,因此每个缓冲区只能有一个项目可以占用或附加内容。这些名为mutex和mutex2。 emptycount和fillcount分别是从max_buffer_size和0开始使用的计数sems。

消费者在消费前必须从每个缓冲区中取一封信。他们这样做的顺序并不重要,所以我试图告诉每个人先从缓冲区取一些东西,然后再放入另一个缓冲区。我在每个缓冲区的消费者代码之外设置了一个从3开始的信号量。这些是sems上下,用于确保一次只有3个消费者可以进入任何一个缓冲区。

变量countUpper和countLower应该计算当时每个缓冲区中有多少项。

我确定我的sems放错了但是我找不到哪里,我对线程很新。队列是抽象的,在另一个文件中,但它们正常工作。另外,我只生成小写字母atm,但这无关紧要。

感谢任何帮助。

#include "pq.h"

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

#define MAX_CPRODUCER 3
#define MAX_LPRODUCER 3
#define MAX_CONSUMER 10
#define MAX_INT 2147483647

// Is the structure for the items produced by the producer thread
typedef struct product product_t;
struct product {
  char item;
  int PrdPID;
  unsigned int sequence_num;
};

typedef struct pq_struct pq_struct_t;
struct pq_struct
{
    pq_t lower;
    pq_t upper;    
};

int countUpper, countLower;
sem_t mutex, fillCount, emptyCount;
sem_t mutex2, fillCount2, emptyCount2;
sem_t lower, upper;


//Produce a letter to put in
product_t *produce(int pid, unsigned int count)
{   
    product_t *aProduct = malloc( sizeof(*aProduct) );
    aProduct->item = (char)(rand() % 26 + 97); //To get ascii lowercase
    aProduct->PrdPID = pid;
    aProduct->sequence_num = count;

    return aProduct;
}

//Append the letter to the buffer
void append(void *pq, product_t *aProduct)
{
    //Insert letter into queue
    //Key is irrelevant and always 1 for this program
    pq_insert((pq_t*)pq, 1, (void*)aProduct);
    //printf("Appended: ID = %d     Count = %d      Letter = %c\n", aProduct->PrdPID, aProduct->sequence_num, aProduct->item);
}

//Take a letter from buffer
product_t *take(void *pq)
{
    //Delete from buffer and place in our consumer product
    product_t *aProduct = (product_t*)pq_delete((pq_t*)pq);
    return aProduct;
}

//Consume the letter
void consume(product_t *aProduct, product_t *theProduct, int id)
{   
    printf("Removing: ID = %d     Count = %d      Letter = %c\n", aProduct->PrdPID,    aProduct->sequence_num, aProduct->item); 
    free(aProduct);  //Takes place of consume
    free(theProduct);
}

//Producer function for uppercase buffer
void *ProducerCapital (void *pq) 
{ 
    pq_t *upperPq = pq;
    product_t *cProduct = NULL;
    unsigned int count = 0;

     for (;;) 
     { 
        cProduct = produce(1, ++count);
        sem_wait(&emptyCount);
            sem_wait(&mutex);
                //Make new item
                append(upperPq, cProduct);
                ++countUpper;
                // 
            sem_post(&mutex);
        sem_post(&fillCount);
    }
pthread_exit (NULL);
} 
//Producer thread for lowercase buffer
void *ProducerLower (void *pq) 
{ 
    pq_t *lowerPq = pq;
    product_t *lProduct = NULL;
    unsigned int count = 0;

     for (;;) 
     { 
        lProduct = produce(1, ++count);
        sem_wait(&emptyCount2);
            sem_wait(&mutex2);
                //Make new item
                append(lowerPq, lProduct);
                ++countLower;
                // 
            sem_post(&mutex2);
        sem_post(&fillCount2);
    }
pthread_exit (NULL);
} 

void ConsumeUpper(pq_t *pqUpper, product_t *capProd)
{
    sem_wait(&fillCount);
           sem_wait(&mutex);
               //Take Item
               capProd = (product_t*)take((void*)pqUpper);
               //    
           sem_post(&mutex);
    sem_post(&emptyCount);

}

void ConsumeLower(pq_t *pqLower, product_t *lowProd)
{
    sem_wait(&fillCount2);
           sem_wait(&mutex2);
               //Take Item
               lowProd = (product_t*)take((void*)pqLower); 
               //    
           sem_post(&mutex2);
    sem_post(&emptyCount2);

}

void *Consumer (void *pq) 
{ 
     pq_struct_t *sharePqs = (pq_struct_t*)pq;
     product_t *capitalProduct = NULL;
     product_t *lowerProduct = NULL;

     for (;;) 
     {  

        if(countUpper < countLower)
        {
            sem_wait(&lower);
            --countLower;
            ConsumeLower(&sharePqs->lower, capitalProduct);
            sem_post(&lower);

            sem_wait(&upper);
            --countUpper;
            ConsumeUpper(&sharePqs->upper, capitalProduct);
            sem_post(&upper);
        }
        else
        {   
            sem_wait(&upper);
            --countUpper;
            ConsumeUpper(&sharePqs->upper, capitalProduct);
            sem_post(&upper);

            sem_wait(&lower);
            --countLower;
            ConsumeLower(&sharePqs->lower, capitalProduct);
            sem_post(&lower);
        }

        consume(capitalProduct, lowerProduct , 2); 
    }
pthread_exit (NULL);
} 

int main () 
{ 
    //Create queue
    pq_struct_t my_pqs;

    //Initialize the queue
    pq_init(&my_pqs.upper);
    pq_init(&my_pqs.lower);

    pthread_t cProducers[MAX_CPRODUCER];
    pthread_t lProducers[MAX_LPRODUCER]; 
    pthread_t consumers[MAX_CONSUMER];
    srand(time(NULL)); // randomize random function call

    int i, code; 

    countUpper = 0;
    countLower = 0;
    sem_init(&mutex, 0, 1);
    sem_init(&fillCount, 0, 0);
    sem_init(&emptyCount, 0, MAX_INT);
    sem_init(&mutex2, 0, 1);
    sem_init(&fillCount2, 0, 0);
    sem_init(&emptyCount2, 0, MAX_INT);

    sem_init(&lower, 0, 3);
    sem_init(&upper, 0, 3);


    for (i=0; i<MAX_CONSUMER; ++i) 
    { 
       printf ("In main: creating consumer thread %d\n", i); 
       code = pthread_create(&consumers[i], NULL, Consumer, (void *)&my_pqs);

       if (code) 
       { 
        printf ("Error: pthread_create: %d\n", code); 
        exit (-1);  
       } 
    }

    for (i=0; i<MAX_CPRODUCER; ++i) 
    { 
       printf ("In main: creating producer thread %d\n", i); 
       code = pthread_create(&cProducers[i], NULL, ProducerCapital, (void *)&my_pqs.upper);

       if (code) 
       { 
        printf ("Error: pthread_create: %d\n", code); 
        exit (-1);  
       } 
     } 

    for (i=0; i<MAX_LPRODUCER; ++i) 
    { 
       printf ("In main: creating producer thread %d\n", i); 
       code = pthread_create(&lProducers[i], NULL, ProducerLower, (void *)&my_pqs.lower);

       if (code) 
       { 
        printf ("Error: pthread_create: %d\n", code); 
        exit (-1);  
       } 
     }   
     pthread_exit (NULL);
} 

0 个答案:

没有答案