我正在尝试使用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()
的访问周围添加了信号灯,但是输出没有变化。我该怎么办?
答案 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);
}