// 忽略警告
#define _SCL_SECURE_NO_WARNINGS
#pragma warning(disable : 4996)
#include <assert.h>
#include <iostream>
#include <boost/thread.hpp>
#include <stack>
using namespace boost;
using namespace std;
mutex io_mu;
class my_buffer
{
private:
mutex mu; // 互斥量
condition_variable_any cond_put; // 写如的条件变量
condition_variable_any cond_get; // 读取的条件变量
stack<int> s; // 缓冲区对象
int un_read, capacity;
bool is_full(){ return un_read == capacity; } // 缓冲区满判断
bool is_empty(){ return un_read == 0; } // 缓冲区空判断
public:
my_buffer(size_t n):un_read(0), capacity(n){} // 构造函数
void put(int x) // 写入数据
{
{
mutex::scoped_lock lock(mu); // 锁定互斥量
while (is_full()) // 检查缓冲区是否满
{
{ // 锁定cout输出一条信息
mutex::scoped_lock lock(io_mu);
cout << "full waiting..." << endl;
}
cond_put.wait(mu); // 条件变量等待 cond_put.wait(mu,!bind(&my_buffer::is_full,this));// 参数2:表达式为真继续等待
}// 满足条件,停止等待
s.push(x); // 写入
++un_read;
}// 解锁互斥量,条件变量的通知不需要互斥量锁定
cond_get.notify_one(); // (执行到该条说明s肯定不空)通知可以读取数据
}
void get(int *x) // 读取数据
{
{
mutex::scoped_lock lock(mu); // 锁定互斥量
while (is_empty()) // 检查缓冲区是否空
{
{ // 锁定cout输出一条信息
mutex::scoped_lock lock(io_mu); // consumer先执行则先锁住
cout << "empty waiting..." << endl;
}
cond_get.wait(mu); // 条件变量等待 cond_get.wait(mu,!bind(&my_buffer::is_empty,this));
}// 满足条件,停止等待
*x = s.top(); // 读取
--un_read;
s.pop(); // 出栈
}// 解锁互斥量,条件变量的通知不需要互斥量锁定
cond_put.notify_one(); // (执行到该条说s明肯定不满)通知可以写入数据
}
};
my_buffer buf(5);
// 然后定义两个生产者和消费者
// 生产者
void producer(int n)
{
for (int i = 0; i < n; ++i)
{
{
mutex::scoped_lock lock(io_mu);
cout << "put: " << i << endl; // cout只是为了接下来的bug.put提供消息
}
buf.put(i); // 写入数据
}
}
// 消费者
void consumer(int n)
{
int x;
for (int i = 0; i < n; ++i)
{
buf.get(&x);
mutex::scoped_lock lock(io_mu);
cout << "get: " << x << endl;
}
}
int main()
{
// 条件变量condition_variable; condition_variable_any(适应更多的互斥类型);
// 拥有条件变量cv的线程先锁定互斥量,循环检查某个条件,否则cv的成员函数wait()等待直到条件满足
// 当其他线程满足条件变量的条件时,调用notify_one或notify_all通知相关线程继续执行
// 1.mutex::scoped_lock lock(io_mu);四处同一时刻只有一处加锁
// 2 例如.t1线程持有io_mu对象后,在自己的时间片里执行临界区代码;t1时间片到了会切换到其他线程t2
// 3.在t2的时间片期间执行代码,如果t2也有mutex::scoped_lock lock(io_mu),而t1还没执行完{临界区的代码},则t2会在该行代码处等待直到时间片用完
// 4.当再次切换到t1时,t1继续执行临界区剩下的代码,直到走出临界区(跳出lock作用域),当t1走完时间片后,且没有再持有io_mu对象时,切换到t2时间片执行mutex::scoped_lock lock(io_mu),上锁
// 5.t2线程执行2步骤..
thread t1(producer,20); // 一个生产者线程
thread t2(consumer,10); // 两个消费者线程
thread t3(consumer,10);
// producer 和 consumer随机先一个执行
t1.join();
t2.join();
t3.join();
return 0;
}