在下面的多生产者和单消费者固定大小队列实现中,我看到该队列被生产者覆盖。
为什么队列被覆盖?
目前,我不是在看代码的性能,而是希望看到所推送的每个项目都已消耗并且没有丢失。
如何将其扩展到多产品多消费者?
#include <iostream>
#include <thread>
#include <mutex>
#include <utility>
#include <ctime>
#include <condition_variable>
#include <stdlib.h>
#include <unistd.h>
#include <atomic>
using namespace std;
enum class returncode { QUEUE_EMPTY, QUEUE_FULL,SUCCESS } ;
atomic_long d;
class Queue {
private:
long* qdata;
atomic_size_t length;
atomic_size_t head;
atomic_size_t tail ;
atomic_size_t size;
std::mutex qmutex;
std::condition_variable qcond ;
public:
Queue(size_t len): length(len)
{
qdata=new long[length] ;
head=0;
tail=0;
size=0;
srand(time(NULL));
}
bool isfull()
{
if( size == length )
return true;
return false;
}
bool isempty()
{
if(size == 0)
return true;
return false;
}
returncode push(long data)
{
std::unique_lock<std::mutex> qguard(qmutex);
if(size == length) //if isfull
return returncode::QUEUE_FULL ;
qdata[head]=data;
head = (head+1) % length;
size += 1 ;
qcond.notify_one();
qguard.unlock(); //Should the unlock come before notify_one?
return returncode::SUCCESS;
}
//Its the users responsibility to check isempty before calling front.
//Read function
long front(void)
{
std::unique_lock<std::mutex> qguard(qmutex);
//if isempty
if( size == 0 )
return 0;
long d=qdata[tail];
return d;
}
void pop(void)
{
std::thread::id thisthreadid = std::this_thread::get_id();
std::unique_lock<std::mutex> qguard(qmutex);
while(size == 0 ) // check condition to be safe against spurious wakes
{
qcond.wait(qguard);// release lock and go join the waiting thread queue
return;
}
tail =(tail+1) % length;
size -= 1;
}
};
void produce(Queue* q)
{
while(true)
{
d++;
q->push(d) ;
//sleep(1);
}
}
void consume(Queue* q)
{
while(true){
//usleep(1000);
cout <<"Consume: Pop " << q->front() <<endl;
q->pop();
}
}
int main(int argc, char** argv )
{
Queue q(50);
d=0;
int nprods=4;
int nconsu=1;
std::thread producers[nprods];
std::thread consumers[nconsu];
for (int i=0; i < nprods ; ++i)
producers[i] = std::thread(produce, &q);
for (int i=0; i < nconsu ; ++i)
consumers[i] = std::thread(consume, &q);
for (int i=0; i<nprods; ++i)
producers[i].join();
for (int i=0; i<nconsu; ++i)
consumers[i].join();
return 0;
}
输出:
Consume: Pop 1 Consume: Pop 2 ... Sequential all upto the queue size and then q is over written. Consume: Pop 49 Consume: Pop 50 Consume: Pop 51 Consume: Pop 52 Consume: Pop 53 Consume: Pop 54 Consume: Pop 55 Consume: Pop 56 Consume: Pop 64 --> 57 to 63 lost Consume: Pop 72 --> 65 to 71 lost Consume: Pop 81 Consume: Pop 89 Consume: Pop 97 Consume: Pop 105