Need help in implementing the Producer-Consumer problem with pthread and semaphore

拈花ヽ惹草 提交于 2019-12-08 15:20:49

问题


I am trying to implement the Producer and Consumer problem in C++ using pthread and semaphore. I have one Producer and two consumers. My producer reads a string from a file and stores it in a queue character by character. The consumers read from the string and store in a char character also one by one. The problem is that only one of my Consumer is reading from the queue, other is not and its array is remaining empty. How do I fix this problem. Here is my program:

#include<iostream>
#include<pthread.h>
#include<fstream>
#include<unistd.h>
#include<semaphore.h>
#include<queue>

// define queue size
#define QUEUE_SIZE 5

// declare and initialize semaphore and read/write counter
static sem_t mutex,mutex1;
//static int counter = 0;

// Queue for saving characters
static std::queue<char> charQueue;

// indicator for end of file
static bool endOfFile = false;

// save arrays
static char consumerArray1[100];
static char consumerArray2[100];


void *Producer(void *ptr)
{
    int i=0;
    std::ifstream input("string.txt");
    char temp;
    while(input>>temp)
    {
        sem_wait(&mutex);
        charQueue.push(temp);
        sem_post(&mutex1);
        sem_post(&mutex);
        //counter++;
        std::cout<<"Procuder Index: "<<i<<std::endl;
        i++;

        sleep(6);
    }
    endOfFile = true;
    pthread_exit(NULL);
}

void *Consumer1(void *ptr)
{
    std::cout<<"Entered consumer 1:"<<std::endl;
    int i = 0;
    sem_wait(&mutex1);
    //while(charQueue.empty());
    sem_post(&mutex1);
    while(!endOfFile)// || !charQueue.empty())
    {
        sem_wait(&mutex1);


        sem_wait(&mutex);

        std::cout<<"Consumer1 index:"<<i<<" char: "<<charQueue.front()<<std::endl;
        consumerArray1[i] = charQueue.front();
        charQueue.pop();
        //std::cout<<charQueue.size()<<std::endl;

        sem_post(&mutex1);
        i++;
        //counter--;

        sem_post(&mutex);
        sleep(2);
    }
    consumerArray1[i] = '\0';
    pthread_exit(NULL);
}

void *Consumer2(void *ptr)
{
    std::cout<<"Entered consumer 2:"<<std::endl;
    int i = 0;
    sem_wait(&mutex1);
    //while(charQueue.empty());
    sem_post(&mutex1);

    while(!endOfFile)//  || charQueue.empty())
    {
        sem_wait(&mutex1);


        sem_wait(&mutex);

        std::cout<<"Consumer2 index: "<<i<<" char: "<<charQueue.front()<<std::endl;
        consumerArray2[i] = charQueue.front();
        charQueue.pop();
        sem_post(&mutex1);
        i++;
        //counter--;

        sem_post(&mutex);
        sleep(4);
    }
    consumerArray2[i] = '\0';
    pthread_exit(NULL);
}

int main()
{
    pthread_t thread[3];
    sem_init(&mutex,0,1);
    sem_init(&mutex1,0,1);
    pthread_create(&thread[0],NULL,Producer,NULL);
    int rc = pthread_create(&thread[1],NULL,Consumer1,NULL);
    if(rc)
    {
        std::cout<<"Thread not created"<<std::endl;
    }
    pthread_create(&thread[2],NULL,Consumer2,NULL);
    pthread_join(thread[0],NULL);pthread_join(thread[1],NULL);pthread_join(thread[2],NULL);
    std::cout<<"First array: "<<consumerArray1<<std::endl;
    std::cout<<"Second array: "<<consumerArray2<<std::endl;
    sem_destroy(&mutex);
    sem_destroy(&mutex1);
    pthread_exit(NULL);
}

Edit: I added semaphore around the access of charQueue.empty() and charQueue.push() as well, but no change in output. what else should I do?


回答1:


You have the same problem that you had before. Your Consumer1 function can call charQueue.empty while your Producer function can be calling charQueue.push(temp);. You may not access an object in one thread while another thread is, or might be, modifying it. You either need to protect charQueue with a mutex, with a semaphore, or with some other form of synchronization primitive.

Again, the compiler is free to optimize code like this:

while(charQueue.empty());

To code like this:

if (charQueue.empty()) while (1);

Why? Because your code may be accessing charQueue at any time. And it is expressly prohibited for one thread to modify an object while another thread may be accessing it. Therefore, the compiler is permitted to assume that charQueue will not be modified while this loop is executing and so there is no need to check it for emptiness more than once.

You have sempahores. Use them to ensure that only one thread might touch charQueue at a time.




回答2:


Using guidelines from @DavidSchwartz I made this code that is working. Please suggest me a better way to implement it, as in if there are better and safer ways to do the things I have done. Sorry for me not getting most of the comments and answer as this is my first code using pthreads and semaphore. So, please bear with me:

#include<iostream>
#include<pthread.h>
#include<fstream>
#include<unistd.h>
#include<semaphore.h>
#include<queue>

// define queue size
#define QUEUE_SIZE 5

// declare and initialize semaphore and read/write counter
static sem_t mutex,mutex1;
//static int counter = 0;

// Queue for saving characters
static std::queue<char> charQueue;

// indicator for end of file
static bool endOfFile = false;

// save arrays
static char consumerArray1[100];
static char consumerArray2[100];


void *Producer(void *ptr)
{
    int i=0;
    std::ifstream input("string.txt");
    char temp;
    while(input>>temp)
    {
        sem_wait(&mutex);
        charQueue.push(temp);
        sem_post(&mutex1);
        sem_post(&mutex);

        i++;

        sleep(6);
    }

    endOfFile = true;
    sem_post(&mutex1);
    pthread_exit(NULL);
}

void *Consumer1(void *ptr)
{

    int i = 0;
    sem_wait(&mutex1);
    bool loopCond = endOfFile;
    while(!loopCond)
    {

        if(endOfFile)
        {

            loopCond = charQueue.empty();
            std::cout<<loopCond<<std::endl;
            sem_post(&mutex1);
        }
       sem_wait(&mutex1);


        sem_wait(&mutex);


        if(!charQueue.empty())
        {

            consumerArray1[i] = charQueue.front();
            charQueue.pop();
            i++;
        }        
        if(charQueue.empty()&&endOfFile)
        {

            sem_post(&mutex);
            sem_post(&mutex1);
            break;
        }  

        sem_post(&mutex);
        sleep(2);

    }

    consumerArray1[i] = '\0';
    pthread_exit(NULL);

}

void *Consumer2(void *ptr)
{

    int i = 0;
    sem_wait(&mutex1);
    bool loopCond = endOfFile;
    while(!loopCond)
    {

        if(endOfFile)
        {

            loopCond = charQueue.empty();
            std::cout<<loopCond<<std::endl;
            sem_post(&mutex1);
        }
        sem_wait(&mutex1);


        sem_wait(&mutex);


        if(!charQueue.empty())
        {

            consumerArray2[i] = charQueue.front();
            charQueue.pop();
            i++;
        }  
        if(charQueue.empty()&& endOfFile)
        {

            sem_post(&mutex);
            sem_post(&mutex1);
            break;
        }  



        sem_post(&mutex);
        sleep(4);

    }

    consumerArray2[i] = '\0';
    pthread_exit(NULL);

}

int main()
{
    pthread_t thread[3];
    sem_init(&mutex,0,1);
    sem_init(&mutex1,0,1);
    pthread_create(&thread[0],NULL,Producer,NULL);
    int rc = pthread_create(&thread[1],NULL,Consumer1,NULL);
    if(rc)
    {
        std::cout<<"Thread not created"<<std::endl;
    }
    pthread_create(&thread[2],NULL,Consumer2,NULL);
    pthread_join(thread[0],NULL);pthread_join(thread[1],NULL);pthread_join(thread[2],NULL);
    std::cout<<"First array: "<<consumerArray1<<std::endl;
    std::cout<<"Second array: "<<consumerArray2<<std::endl;
    sem_destroy(&mutex);
    sem_destroy(&mutex1);
    pthread_exit(NULL);
}


来源:https://stackoverflow.com/questions/55722150/need-help-in-implementing-the-producer-consumer-problem-with-pthread-and-semapho

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!