在使用pthread和信号量实现生产者-消费者问题时需要帮助

时间:2019-04-17 07:27:59

标签: c++ operating-system pthreads semaphore

我正在尝试使用pthread和semaphore在C ++中实现生产者和消费者问题。我有一个生产者和两个消费者。我的生产者从文件中读取一个字符串,并将其逐字符存储在队列中。消费者从字符串中读取内容,并一一存储在char字符中。问题是我的使用者中只有一个正在从队列中读取,另一个则不在,并且其数组保持为空。我该如何解决此问题。这是我的程序:

#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);
}

编辑:我还在charQueue.empty()charQueue.push()的访问周围添加了信号灯,但是输出没有变化。我该怎么办?

2 个答案:

答案 0 :(得分:1)

您遇到的问题与以前相同。 Consumer1函数可以调用charQueue.empty,而Producer函数可以调用charQueue.push(temp);。您可能无法在一个线程中访问一个对象,而另一个线程正在或可能正在修改它。您可能需要使用互斥量,信号量或其他某种形式的同步原语来保护charQueue

同样,编译器可以自由地优化如下代码:

while(charQueue.empty());

要这样编码:

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

为什么?因为您的代码可能随时都在访问charQueue。并且明确禁止一个线程修改对象,而另一个线程可能正在访问它。因此,允许编译器假定charQueue在执行此循环时不会被修改,因此无需多次检查其是否为空。

您有经验。使用它们来确保一次只有一个线程可以碰到charQueue

答案 1 :(得分:0)

使用@DavidSchwartz的指南,使此代码有效。请向我建议一种更好的实施方法,就像有更好,更安全的方法来完成我所做的事情一样。对不起,我没有得到大多数评论和答复,因为这是我使用pthreads和semaphore的第一个代码。所以,请忍受我

#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);
}