1.三种关系
1.生产者和生产者互斥关系
2.消费者和消费者互斥关系
3.生产者和消费者同步互斥关系
2.生产者和消费者模型
生产者消费者模型就是通过一个容器来来解决强耦合问题的。(耦合:2个或2个以上事物相互作用,相互影响,以至于两个事物在一起的特性和两个事物单独的特性不同)消费者和生产者之间不进行直接通讯,而是通过阻塞队列来通讯的,生产者的数据不用等消费者处理直接扔给阻塞队列,消费者直接去阻塞队列去取数据。阻塞队列相当于一个缓冲区,平衡了消费者和生产者的处理能力,这个阻塞队列就是为消费者和生产者来解耦的。
3.优点
- 解耦
- 支持并发
- 支持忙闲不均
4.实现简单生产者消费者模型
#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
#include<vector>
using namespace std;
//实现一个生产者消费者模型
//首先得有一个交易场所
vector<int> data;
pthread_mutex_t mutex;
pthread_cond_t cond;
//生产者
void* Product(void* arg)
{
(void)arg;
int count = 0;
while(1){
pthread_mutex_lock(&mutex);
data.push_back(++count) ;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
usleep(666666);
}
return NULL;
}
//消费者
void* Consume(void* arg)
{
(void)arg;
//负责把交易场所中的数据取出来
while(1)
{
//每次取最后一个元素
pthread_mutex_lock(&mutex);
while(data.empty())
{
//1.先释放锁
//2.等待条件就绪
//3.如果条件就绪,重新获取锁
pthread_cond_wait(&cond,&mutex);
}
int result = data.back();
data.pop_back();
printf("result = %d\n",result);
pthread_mutex_unlock(&mutex);
usleep(666666);
}
return NULL;
}
int main()
{
pthread_mutex_init(&mutex,NULL);
pthread_cond_init(&cond,NULL);
pthread_t tid1,tid2;
pthread_create(&tid1,NULL, Product, NULL);
pthread_create(&tid2,NULL, Consume, NULL);
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
return 0;
}
5.基于阻塞队列实现(BlocKingQueue)
BlocKingQueue.hpp
#pragma once
#include<queue>
#include<stdlib.h>
#include<pthread.h>
#include<iostream>
#define NUM 9
using namespace std;
//一般BlockingQueue 都要求长度是有上限的
//如果队列为空,去执行Pop就会堵塞
//如果队列满了,去执行Push也会堵塞
template<class T>
class BlockingQueue
{
private:
void LockQueue()
{
pthread_mutex_lock(&_lock);
}
void UnLockQueue()
{
pthread_mutex_unlock(&_lock);
}
void ProductWait()
{
pthread_cond_wait(&_full,&_lock);
}
void ConsumeWait()
{
pthread_cond_wait(&_empty,&_lock);
}
void NotifyProduct()
{
pthread_cond_signal(&_full);
}
void NotifyConsume()
{
pthread_cond_signal(&_empty);
}
bool IsEmpty()
{
return _queue.size() == 0;
}
bool IsFull()
{
return _queue.size() == _cap;
}
public:
BlockingQueue(int cap = NUM)
:_cap(cap)
{
pthread_mutex_init(&_lock,NULL);
pthread_cond_init(&_full,NULL);
pthread_cond_init(&_empty,NULL);
}
~BlockingQueue()
{
pthread_mutex_destroy(&_lock);
pthread_cond_destroy(&_full);
pthread_cond_destroy(&_empty);
}
void Push(const T& data)
{
LockQueue();
while(IsFull())
{
NotifyConsume();
cout<<"queue is Full, notify consume data, product stop--size:"<<_queue.size()<<endl;
ProductWait();
}
_queue.push(data);
UnLockQueue();
}
void Pop(T& data)
{
LockQueue();
while(IsEmpty())
{
NotifyProduct();
cout<<"queue is Empty, notify product data,consume stop--size:"<<_queue.size()<<endl;
ConsumeWait();
}
data = _queue.front();
_queue.pop();
UnLockQueue();
}
private:
queue<T> _queue;
int _cap;
pthread_mutex_t _lock;
pthread_cond_t _full;
pthread_cond_t _empty;
};
#include<iostream>
#include<unistd.h>
#include<pthread.h>
#include"blockingqueue.hpp"
using namespace std;
void* producter(void* arg)
{
BlockingQueue<int>* p = (BlockingQueue<int>*) arg;
srand(time(NULL));
while(1)
{
int data = rand()%100;
p->Push(data);
cout<<"product data: "<<data<<endl;
usleep(666666);
}
}
void* consumer(void* arg)
{
BlockingQueue<int>* p = (BlockingQueue<int>*) arg;
int data;
while(1)
{
p->Pop(data);
cout<<"consumer data: "<<data<<endl;
usleep(666666);
}
}
int main()
{
pthread_t tid1,tid2;
BlockingQueue<int> p;
pthread_create(&tid2,NULL,consumer,&p);
pthread_create(&tid1,NULL,producter,&p);
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
return 0;
}
6.基于循环队列实现(RingQueue)
POSIX信号量和SystemV信号量作用相同,都是用于同步操作,达到无冲突的访问共享资源目的。 但POSIX可以用于线程间同步。
信号量其实就是一个计数器
RingQueue.hpp
#pragma once
#include<iostream>
#include<vector>
#include<stdlib.h>
#include<semaphore.h>
#include<pthread.h>
#define NUM 9
using namespace std;
template<class T>
class RingQueue{
public:
RingQueue(int cap = NUM)
:_cap(cap)
{
_q.resize(cap);
sem_init(&data_sem,0,0);//初始化信号量,第二个0表示进程间共享
sem_init(&space_sem,0,cap);//第三个参数表示信号量初始值
consume_step = 0;
product_step = 0;
}
~RingQueue()
{
sem_destroy(&data_sem);//销毁信号量
sem_destroy(&space_sem);
}
void Push(const T& data)
{
sem_wait(&space_sem);//等待信号量,会将信号量的值减一
_q[consume_step] = data;
++consume_step;
consume_step %= _cap;
sem_post(&data_sem);//发布信号量,会将信号量的值加一
}
void Pop(T& data)
{
sem_wait(&data_sem);
data = _q[product_step];
++product_step;
product_step %= _cap;
sem_post(&space_sem);
}
private:
vector<T> _q;
int _cap;
sem_t data_sem;
sem_t space_sem;
int consume_step;
int product_step;
};
#include<iostream>
#include<unistd.h>
#include<pthread.h>
#include"RingQueue.hpp"
using namespace std;
void* producter(void* arg)
{
RingQueue<int>* p = (RingQueue<int>*) arg;
srand(time(NULL));
while(1)
{
int data = rand()%100;
p->Push(data);
cout<<"product data: "<<data<<endl;
sleep(1);
}
}
void* consumer(void* arg)
{
RingQueue<int>* p = (RingQueue<int>*) arg;
int data;
while(1)
{
p->Pop(data);
cout<<"consumer data: "<<data<<endl;
sleep(1);
}
}
int main()
{
pthread_t tid1,tid2;
RingQueue<int> p;
pthread_create(&tid2,NULL,consumer,&p);
pthread_create(&tid1,NULL,producter,&p);
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
return 0;
}