#include <thread>
#include <mutex>
#include <queue>
#include <iostream>
using namespace std;
#define LOOP_TIMES 100
void test1() {
	mutex mtx;
	int res = 0;
	thread t1([&]() {
		for (int i = 0; i < LOOP_TIMES;i++) {
			this_thread::sleep_for(chrono::milliseconds(1));
			res = res + 1;
		}
	});
	thread t2([&]() {
		for (int i = 0; i < LOOP_TIMES; i++) {
			this_thread::sleep_for(chrono::milliseconds(1));
			mtx.lock();
			res = res - 1;
			mtx.unlock();
		}
	});
	t1.join();
	t2.join();
	std::cout << "test1:: res:: " << res  << " mutexsize::" << sizeof(mutex) << endl;
}
void test2() {
	recursive_mutex mtx;
	int res = 0;
	thread t1([&]() {
		for (int i = 0; i < LOOP_TIMES / 10; i++) {
			this_thread::sleep_for(chrono::milliseconds(i));
			lock_guard<recursive_mutex> lock(mtx);
			res = res + 1;
		}
	});
	thread t2([&]() {
		for (int i = 0; i < LOOP_TIMES / 10; i++) {
			this_thread::sleep_for(chrono::milliseconds(i));
			unique_lock<recursive_mutex> lock(mtx);
			res = res - 1;
		}
	});
	t1.join();
	t2.join();
	std::cout << "test2:: res:: " << res << " lock_guard::" << sizeof(lock_guard<mutex>)
		<< " unique_lock::" << sizeof(unique_lock<mutex>) << endl;
}
void test3() {
	mutex mtx;
	int res = 0;
	int error_count = 0;
	queue<int> mq;
	thread t1([&]() {
		for (int i = 0; i < LOOP_TIMES; i++) {
			this_thread::sleep_for(chrono::milliseconds(i));
			lock_guard<mutex> lock(mtx);
			mq.push(i / 2);
			res = res + 1;
		}
	});
	thread t2([&]() {
		int a = 0;
		for (int i = 0; i < LOOP_TIMES;) {
			this_thread::sleep_for(chrono::milliseconds(a));
			unique_lock<mutex> lock(mtx);
			if (mq.empty()) {
				error_count++;
				continue;
			}
			i++;
			a = mq.front();
			mq.pop();
			res = res - 1;
		}
	});
	t1.join();
	t2.join();
	std::cout << "test3:: res:: " << res << " error_count::" << error_count << endl;
}
int main() {
	/*
		进程是房子，线程是住在房子里的人，厕所、厨房...是房子里的共享资源。
	*/
	test1();
	test2();
	/*
	mutex 原子性 排队性
	//保证资源的正确使用，如一个厕所只能一个人用
		//递归锁可以让前面的人重复上锁，避免函数递归时解锁出错
	//排队等待前一个人离开，才能使用
		//超时锁，可以先进入自旋，超时后阻塞
	*/
	test3();
	/* 
		锁 如果存在单向依赖，无法保证资源是否存在，会空转CPU
		生产者知道什么时候有资源，消费者知道什么时候没有资源
		消费者上锁等待，生产者解锁通知， 锁只能自己锁自己解锁
	*/
	
	return 0;
}