#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
#include <unistd.h>
#include <vector>
//实现了一个有界缓冲区(Bounded Buffer)的生产者-消费者模型。
/*主函数创建了一个大小为 10 的有界缓冲区 bb。
创建一个生产者线程和三个消费者线程。
生产者线程在循环中生产数据,消费者线程从缓冲区中消费数据,直到生产者生产完所有数据,并且所有消费者线程都消费完数据。
这个模型通过互斥量和条件变量实现了线程之间的同步与通信,确保生产者不会在缓冲区满时继续生产,消费者不会在缓冲区空时继续消费,从而保证了线程安全的操作。*/
using namespace std;
const int MAX_NUM =10000;
class BoundedBuffer{
public:
//初始化缓冲区的大小为 n,并设置相关成员变量。
BoundedBuffer(size_t n){
array_.resize(n);
start_pos_=0;
end_pos_=0;
pos_=0;
}
//生产者将整数 n 放入缓冲区
void Produce(int n){
{
//对互斥量 mtx_ 上锁,保护共享资源。
std::unique_lock<std::mutex> lock(mtx_);
//条件变量 not_full_ 等待,直到缓冲区不满。
not_full_.wait(lock,[=]{ return pos_ < array_.size();});
usleep(1000 * 400);
//将数据 n 放入缓冲区,并更新 end_pos_。
array_[end_pos_]= n;
end_pos_=(end_pos_+1) %array_.size();
// 增加 pos_ 计数,并输出当前缓冲区中的位置信息。
++pos_;
cout<<"Produce pos:" <<pos_ <<endl;
}
//解锁互斥量后,使用 not_empty_.notify_one(); 通知消费者缓冲区非空。
not_empty_.notify_one();
}
//消费者从缓冲区中取出数据。
int Consume(){
// 对互斥量 mtx_ 上锁。
std::unique_lock<std::mutex> lock(mtx_);
//条件变量 not_empty_ 等待,直到缓冲区不空。
not_empty_.wait(lock,[=]{return pos_ > 0 ;});
usleep(1000*400);
// 从缓冲区取出数据,并更新 start_pos_。
int n = array_[start_pos_];
start_pos_ = (start_pos_ +1) %array_.size();
//减少 pos_ 计数,并输出当前缓冲区中的位置信息。
--pos_;
cout<< "Consume pos:" <<pos_ <<endl;
lock.unlock();
//解锁互斥量后,使用 not_full_.notify_one(); 通知生产者缓冲区不满。
not_full_.notify_one();
return n;
}
private:
//存储实际的数据元素。其大小由构造函数初始化时设定的 n 决定,表示缓冲区的容量。在这里,array_ 是一个整数类型的向量,用于存储生产者生产的数据和消费者消费的数据。
std::vector<int> array_;
//记录缓冲区中起始位置的索引。生产者将数据放入缓冲区时,从 start_pos_ 指示的位置开始放置数据。
size_t start_pos_;
//记录缓冲区中结束位置的索引。生产者将数据放入缓冲区时,放置数据后更新 end_pos_,表示新数据的位置。
size_t end_pos_;
//记录当前缓冲区中的有效元素个数。这个变量在生产者生产数据和消费者消费数据时被更新,以确保缓冲区中数据的正确管理。
size_t pos_;
std::mutex mtx_;
std::condition_variable not_full_;
std::condition_variable not_empty_;
};
// // 创建一个大小为 10 的有界缓冲区对象
BoundedBuffer bb(10);
std::mutex g_mtx;
/*Producer() 函数:
生产者线程函数,不断地生产数据,直到生产完100个数据。
调用 bb.Produce(n) 将数据 n 放入缓冲区。
输出生产者生产的数据 n。
当生产完100个数据后,调用 bb.Produce(-1) 表示生产结束。*/
void Producer(){
int n =0;
while(n<100){
// 生产者生产数据 n
bb.Produce(n);
cout << "Producer:" << n <<endl;
n++;
}
// 生产结束的标志
bb.Produce(-1);
}
/*Consumer() 函数:
消费者线程函数,从缓冲区中消费数据。
使用 std::this_thread::get_id() 获取当前线程的 ID。
循环调用 bb.Consume() 消费数据,并输出消费者线程 ID 和消费的数据 n。
当消费到结束标志 -1 时,调用 bb.Produce(-1) 表示消费结束。*/
void Consumer(){
std::thread::id thread_id = std::this_thread::get_id();
int n =0;
do{
消费者消费数据
n=bb.Consume();
cout << "Consumer thread:" <<thread_id <<" =====>" <<n <<endl;
}while(-1 !=n);
bb.Produce(-1);
}
/*创建一个存储线程对象的向量 t。
使用 std::thread(&Producer) 创建一个生产者线程,并加入到向量 t 中。
使用 std::thread(&Consumer) 创建三个消费者线程,并分别加入到向量 t 中。
使用 one.join() 等待所有线程执行结束。
返回 0 表示程序正常结束。*/
int main(){
std::vector<std::thread> t;
t.push_back(std::thread(&Producer));// 创建生产者线程
t.push_back(std::thread(&Consumer));// 创建消费者线程
t.push_back(std::thread(&Consumer));
t.push_back(std::thread(&Consumer));
for(auto &one :t){
one.join();// 等待所有线程结束
}
return 0;
}
/*输出:
*Produce pos:18446744073709551615
Producer:0
Consume pos:18446744073709551614
Consumer thread:4 =====>0
Consume pos:18446744073709551613
Consumer thread:5 =====>0
Consume pos:18446744073709551612
Consumer thread:3 =====>0
Consume pos:18446744073709551611
Consumer thread:4 =====>0
Consume pos:18446744073709551610
Consumer thread:5 =====>0
Consume pos:18446744073709551609
Consumer thread:3 =====>0
Consume pos:18446744073709551608
Consumer thread:4 =====>0
Consume pos:18446744073709551607
Consumer thread:5 =====>0
Consume pos:18446744073709551606
Consumer thread:3 =====>0
Consume pos:18446744073709551605
Consumer thread:4 =====>0
Consume pos:18446744073709551604
Consumer thread:5 =====>0
Consume pos:18446744073709551603
Consumer thread:3 =====>0
Consume pos:18446744073709551602
Consumer thread:4 =====>0
Consume pos:18446744073709551601
Consumer thread:5 =====>0
**/