基于阻塞队列(条件变量 + 锁)的生产者消费者模型
BlockQueue.hpp (阻塞队列)
c++
#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <vector>
#include <queue>
#include "sem.hpp"
#include "Mutex.hpp"
#include "Cond.hpp"
using namespace std;
#define BLOCKQUEUESIZE 5
template <class T>
class BlockQueue
{
public:
BlockQueue(int num = BLOCKQUEUESIZE)
:num_(num)
{}
void push(const T& in)
{
T t = in;
lock_Guard mtx(mtx_);
if(isFull())
cv_space_.Wait(mtx);
block_queue_.push(t);
cv_data_.notify_one();
}
T pop()
{
lock_Guard mtx(mtx_);
if(isEmpyt())
cv_data_.Wait(mtx);
T t = block_queue_.front();
block_queue_.pop();
cv_space_.notify_one();
return t;
}
bool isEmpyt() {return block_queue_.empty();}
bool isFull() {return block_queue_.size() == num_;}
private:
queue<T> block_queue_;
int num_;
Mutex mtx_;
Condition_variable cv_data_;
Condition_variable cv_space_;
};
Cond.hpp (封装条件变量)
c++
#include <iostream>
#include <cstdlib>
#include "Mutex.hpp"
class Condition_variable
{
public:
Condition_variable()
{
pthread_cond_init(&cond_,nullptr);
}
void Wait(lock_Guard& lg)
{
pthread_cond_wait(&cond_,lg.getMutex());
}
void notify_one()
{
pthread_cond_signal(&cond_);
}
void notify_all()
{
pthread_cond_broadcast(&cond_);
}
~Condition_variable()
{
pthread_cond_destroy(&cond_);
}
private:
pthread_cond_t cond_;
};
Mutex.hpp (封装锁)
c++
#include <iostream>
#include <cstdlib>
#ifndef MUTEX_HPP
#define MUTEX_HPP
class Mutex
{
public:
Mutex()
{
pthread_mutex_init(&mutex_, nullptr);
}
void lock()
{
pthread_mutex_lock(&mutex_);
}
void unlock()
{
pthread_mutex_unlock(&mutex_);
}
pthread_mutex_t* getMutex()
{
return &mutex_;
}
~Mutex()
{
pthread_mutex_destroy(&mutex_);
}
Mutex(const Mutex& mtx) = delete;
Mutex& operator=(const Mutex& mtx) = delete;
private:
pthread_mutex_t mutex_;
};
class lock_Guard
{
public:
lock_Guard(Mutex& mutex)
:mutex_(mutex)
{
mutex_.lock();
}
~lock_Guard()
{
mutex_.unlock();
}
pthread_mutex_t* getMutex()
{
return mutex_.getMutex();
}
lock_Guard(const lock_Guard& lg) = delete;
lock_Guard& operator=(const lock_Guard& lg) = delete;
private:
Mutex& mutex_;
};
#endif
main.cc
c++
#include "BlockQueue.hpp"
#include <pthread.h>
#define CUSTOMERSIZE 2
#define PRODUCTORSIZE 1
class Task
{
public:
Task(int x,int y)
:x_(x),y_(y)
{}
int operator()()
{
return x_ + y_;
}
int x_;
int y_;
};
struct MyThread
{
BlockQueue<Task>* rg;
string name;
};
void* customer(void* args)
{
MyThread* mt = (MyThread*)args;
BlockQueue<Task>* rg = mt->rg;
string name = mt->name;
sleep(5);
while(true)
{
Task task = rg->pop();
int ans = task();
cout << name << ": " << task.x_ << " + " << task.y_ << " = " << ans << endl;
}
return nullptr;
}
void* productor(void* args)
{
MyThread* mt = (MyThread*)args;
BlockQueue<Task>* rg = mt->rg;
string name = mt->name;
while(true)
{
int x = rand()%100+1;
usleep(100);
int y = rand()%100+1;
rg->push(Task(x,y));
cout << name << ": " << x << " + " << y << " = ?"<<endl;
sleep(1);
}
return nullptr;
}
int main()
{
srand(time(NULL));
BlockQueue<Task> rg(3);
MyThread c_mt[CUSTOMERSIZE];
MyThread p_mt[PRODUCTORSIZE];
pthread_t c[CUSTOMERSIZE];
pthread_t p[PRODUCTORSIZE];
for(int i=0;i<CUSTOMERSIZE;++i)
{
c_mt[i].rg = &rg;
string name = "customer ";
name += to_string(i+1);
c_mt[i].name=name;
pthread_create(c+i,nullptr,customer,(void*)(c_mt+i));
}
for(int i=0;i<PRODUCTORSIZE;++i)
{
p_mt[i].rg = &rg;
string name = "productor ";
name += to_string(i+1);
p_mt[i].name=name;
pthread_create(p+i,nullptr,productor,(void*)(p_mt+i));
}
for(int i=0;i<CUSTOMERSIZE;++i)
{
pthread_join(c[i],nullptr);
}
for(int i=0;i<PRODUCTORSIZE;++i)
{
pthread_join(p[i],nullptr);
}
return 0;
}
makefile
makefile
blockQueue:main.cc
g++ -o $@ $^ -std=c++11 -l pthread
.PHONY:clean
clean:
rm -f blockQueue