生产者与消费者模型
通过一个容器来解决生产者与消费者之间的强耦合问题:
生产者与消费者之间不直接通讯,而是通过无锁阻塞队列来进行通讯;生产者生产完数据后不用等待消费者处理,而是直接放到阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列取。 阻塞队列相当于一个缓冲区,平衡了生产者与消费者的处理能力,用来解耦合。
优点:
- 支持忙闲不均
- 支持并发(先保证安全队列)
- 解耦合(让两个模块间减少关联)
BlockingQueue代码实现
注意:
- 生产者或消费者之间具备互斥关系
- 生产者与消费者之间具备同步+互相hi关系
- 先进先出
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<queue>
#include<pthread.h>
#include<unistd.h>
using namespace std;
#define MAX_QUE 10
#define MAX_THR 4
class BlockQueue{
private:
queue<int> _queue;
int _capacity;
pthread_cond_t _cond_pro;//生产者条件变量
pthread_cond_t _cond_con;//消费者条件变量
pthread_mutex_t _mutex;
public:
BlockQueue(int que_num=MAX_QUE):_capacity(que_num){
pthread_mutex_init(&_mutex,NULL);
pthread_cond_init(&_cond_pro,NULL);
pthread_cond_init(&_cond_con,NULL);
}
~BlockQueue(){
pthread_mutex_destroy(&_mutex);
pthread_cond_destroy(&_cond_pro);
pthread_cond_destroy(&_cond_con);
}
bool QueuePush(int &data){
pthread_mutex_lock(&_mutex);
while(_queue.size()==_capacity){
pthread_cond_wait(&_cond_pro,&_mutex);
}
_queue.push(data);
pthread_mutex_unlock(&_mutex);
pthread_cond_signal(&_cond_con);
return true;
}
bool QueuePop(int &data){
pthread_mutex_lock(&_mutex);
while(_queue.size()==0){
pthread_cond_wait(&_cond_con,&_mutex);
}
data=_queue.front();
_queue.pop();
pthread_mutex_unlock(&_mutex);
pthread_cond_signal(&_cond_pro);
return true;
}
};
void *consumer(void *arg){
BlockQueue *queue=(BlockQueue*)arg;
while(1){
int data;
queue->QueuePop(data);
printf("%p..get a data:%d\n",pthread_self(),data);
}
return NULL;
}
void *product(void *arg){
int data=0;
BlockQueue *queue=(BlockQueue*)arg;
while(1){
queue->QueuePush(data);
printf("%p__put a data:%d\n",pthread_self(),data++);
sleep(1);
}
return NULL;
}
int main(){
BlockQueue bq;
pthread_t ptid[MAX_THR],ctid[MAX_THR];
int ret;
for(int i=0;i<MAX_THR;i++){
ret=pthread_create(&ptid[i],NULL,product,(void*)&bq);
if(ret!=0){
cerr<<"pthread create error"<<endl;
return -1;
}
}
for(int i=0;i<MAX_THR;i++){
ret=pthread_create(&ctid[i],NULL,consumer,(void*)&bq);
if(ret!=0){
cerr<<"pthread create error\n"<<endl;
return -1;
}
}
for(int i=0;i<MAX_THR;i++){
pthread_join(ptid[i],NULL);
pthread_join(ctid[i],NULL);
}
return 0;
}
环形生产与消费者模型
#include<iostream>
#include<string>
#include<stdio.h>
#include<unistd.h>
#include<vector>
#include<semaphore.h>
#include<pthread.h>
using namespace std;
#define MAX_THR 4
#define MAX_QN 10
class RingQueue{
private:
vector<int> _queue;
int _capacity;
int _read;
int _write;
sem_t sem_lock;
sem_t sem_con;
sem_t sem_pro;
public:
RingQueue(int max_que=MAX_QN):_capacity(max_que),_queue(max_que),_write(0),_read(0){
sem_init(&sem_lock,0,1);
sem_init(&sem_con,0,0);
sem_init(&sem_pro,0,max_que);
}
~RingQueue(){
sem_destroy(&sem_lock);
sem_destroy(&sem_pro);
sem_destroy(&sem_con);
}
bool QueuePush(int &data){
sem_wait(&sem_pro);
sem_wait(&sem_lock);
_queue[_write]=data;
_write=(_write+1)%_capacity;
sem_post(&sem_lock);
sem_post(&sem_con);
return true;
}
bool QueuePop(int &data){
sem_wait(&sem_con);
sem_wait(&sem_lock);
data=_queue[_read];
_read=(_read+1)%_capacity;
sem_post(&sem_lock);
sem_post(&sem_pro);
return true;
}
};
void *consumer(void *arg){//消费者执行函数
RingQueue *queue=(RingQueue*)arg;
while(1){
int data;
queue->QueuePop(data);
printf("%p***get a data:%d\n",pthread_self(),data);
}
return NULL;
}
void *productor(void *arg){//生产者执行函数
RingQueue *queue=(RingQueue*)arg;
int i=0;
while(1){
queue->QueuePush(i);
printf("%p---put a data:%d\n",pthread_self(),i++);
sleep(1);
}
return NULL;
}
int main(){
RingQueue queue;
pthread_t ctid[MAX_THR],ptid[MAX_THR];
for(int i=0;i<MAX_THR;i++){
int ret=pthread_create(&ctid[i],NULL,consumer,(void*)&queue);
if(ret!=0){
printf("pthread create error\n");
return -1;
}
}
for(int i=0;i<MAX_THR;i++){
int ret=pthread_create(&ptid[i],NULL,productor,(void*)&queue);
if(ret!=0){
printf("pthread create error\n");
return -1;
}
}
for(int i=0;i<MAX_THR;i++){
pthread_join(ctid[i],NULL);
pthread_join(ptid[i],NULL);
}
return 0;
}
线程池
提前创建一批线程(最大数量限制),以及一个线程安全的任务队列,当大量的请求到来后,被添加到任务队列中,而线程池中的线程再不断从任务队列中获取任务进行处理即可。
作用
- 避免大量线程的频繁创建与销毁所带来的时间成本。
- 避免峰值压力下的线程创建过多导致的导致资源耗尽的风险。(创建有最大数量上限)
实现方法
- 一个以上的线程+线程安全的队列
- 使用C++封装一个线程池类,向外提供简单的线程池操作接口
代码实现
#include<iostream>
#include<queue>
#include<stdio.h>
#include<unistd.h>
#include<pthread.h>
#include<stdlib.h>
using namespace std;
//任务类的实现
typedef void(*TaskHandler)(int data);
class ThreadTask{
private:
int _data;
TaskHandler _handler;
public:
ThreadTask(){}
ThreadTask(int data,TaskHandler handler)//构造时给定参数
:_data(data),_handler(handler){}
void SetTask(int data,TaskHandler handler){
_data=data;
_handler=handler;
}
void Run(){
_handler(_data);
}
};
//线程池的实现
#define MAX_THR 5
class ThreadPool{
private:
int thr_num;//线程池中线程的最大数量
queue<ThreadTask> _task_queue;//队列
pthread_mutex_t _mutex;//保护队列的安全操作
pthread_cond_t _cond_con;//实现队列的同步操作---消费者
pthread_cond_t _cond_pro;//实现队列的同步操作---生产者
private:
static void *thr_start(void *arg){//只能洋浦一个函数,如果没有static表示是个类成员函数
ThreadPool *pool=(ThreadPool*)arg;
while(1){
pool->ThreadLock();
while(pool->TaskIsEmpty()){
pool->ThreadWait();
}
ThreadTask tt;
pool->QueuePop(tt);
pool->ThreadUnlock();
tt.Run();
}
return NULL;
}
public:
void ThreadLock(){
pthread_mutex_lock(&_mutex);
}
void ThreadUnlock(){
pthread_mutex_unlock(&_mutex);
}
void ThreadWait(){
pthread_cond_wait(&_cond_con,&_mutex);
}
void ThreadWakeUp(){
pthread_cond_signal(&_cond_con);
}
bool TaskIsEmpty(){
return _task_queue.empty();
}
bool QueuePop(ThreadTask &tt){
tt=_task_queue.front();
_task_queue.pop();
return true;
}
public:
ThreadPool(int max_thr=MAX_THR)
:thr_num(max_thr){}
//线程池的初始化
bool PoolInit(){
pthread_mutex_init(&_mutex,NULL);//锁、条件变量的初始化一定要放在线程创建之前
pthread_cond_init(&_cond_con,NULL);
pthread_cond_init(&_cond_pro,NULL);
for(int i=0;i<thr_num;i++){
pthread_t tid;
int ret=pthread_create(&tid,NULL,thr_start,(void*)this);
if(ret!=0){
cerr<<"pthread create error\n";
return false;
}
pthread_detach(tid);
}
return true;
}
//向任务队列中添加队列
bool TaskPush(ThreadTask &tt){
pthread_mutex_lock(&_mutex);
_task_queue.push(tt);
pthread_mutex_unlock(&_mutex);
pthread_cond_signal(&_cond_con);
return true;
}
};
//调用函数
void test(int data){
srand(data);
int sec=rand()%5;
printf("thread:%p---get data:%d,sleep %d sec\n",pthread_self(),data,sec);
sleep(sec);
}
int main(){
ThreadPool pool;
pool.PoolInit();
for(int i=0;i<10;i++){
ThreadTask task(i,test);
pool.TaskPush(task);
}
while(1){
sleep(1);
}
return 0;
}