#include <iostream>
#include <thread>
#include <mutex>
#include <list>
using namespace std;
#if 0
chrono::milliseconds time(20000); //这个是已毫秒为单位的 所以是20s
this_thread::sleep_for(time); //让当前线程休息20s的意思
#endif
#if 0
互斥锁锁住的代码多少称为锁的 粒度,粒度一般的单位是粗细
① 使用mutex Thread_Mutex; 用锁的变量进行临界资源的保护 eg: Thread_Mutex.lock() Thread_Mutex.unlock();
② 使用lock_guard<mutex> mutex_guard(Thread_Mutex); 类模板进行保护,这个的好处就是你创建这个对象的时候自动上锁,等这个对象离开所在的作用域调用该析构函数自动解锁
lock_guard<mutex> mutex_guard(Thread_Mutex,adopt_lock); 这个函数模板的第二个参数是告诉这个类模板里边的互斥量已经被上锁,不需要在构造函数进行上锁,但是还是会在析构函数中进行解锁的
③ 死锁是发生在两把锁在互相等着对方解锁发生情况 > lock(Thread_Mutex, Thread_Mutex1); //预防死锁的情况 这两把锁都可以进行上锁和解锁,这个函数模板不会发生死锁的情况
④ unique_lock<mutex> mutex_unique(Thread_Mutex); 这个函数模板相对于上边的guard效率上差一点,内存占用多一点,但是更灵活,第二个参数也可以使用adopt_lock来表示已经上锁了
unique_lock<mutex> mutex_unique(Thread_Mutex, try_to_lock); //尝试上锁
if (mutex_unique.owns_lock())
{
//拿到锁执行的代码
}
else
{
//没有拿到锁执行的代码
}
//也可以使用if (mutex_unique.try_lock() == true)来判断是否拿到锁
std::defer_lock也是上边类模板的第二个参数, 他执行完是没有上锁的, 需要程序员利用类模板变量自己手动去上锁, 或者手动去解锁, 可以更加的方便和灵活的操作临界区, 但是析构函数还是会自动解锁的
unique_lock<mutex> mutex_unique(Thread_Mutex, defer_lock);
mutex * pmutex = mutex_unique.release(); 释放锁的控制权,放弃类模板和互斥锁绑定的关系,就是不自动解锁了 这个函数返回的是互斥锁的一个指针,利用这个变量就可以对这个把重新进行操作了
//转移所有权也可以用std::move转移所有权的函数或者可以用函数的临时对象来转移所有权 构造一个新的类变量
1 > lock_guard<mutex> mutex_guard1(move(Thread_Mutex));
2 > std::lock_guard<mutex> ReturnTemObj() //返回临时对象 调用移动构造函数
{
std::lock_guard<mutex> TemGuard(Thread_Mutex);
return TemGuard;
}
lock_guard<mutex> mutex_guard1 = ReturnTemObj();
#endif
class Thread_Test
{
public:
void InMsgRecvQueue() //存入数据线程
{
for (int i = 0; i < 10000 ; i++)
{
lock_guard<mutex> mutex_guard(Thread_Mutex);
unique_lock<mutex> mutex_unique(Thread_Mutex,defer_lock); //尝试上锁
mutex * pmutex = mutex_unique.release(); //释放锁的控制权,放弃类模板和互斥锁绑定的关系,就是不自动解锁了 这个函数返回的是互斥锁的一个指针
//Thread_Mutex.lock();
m_listMsgRecvQueue.push_back(i); //往链表容器中加入数据
//Thread_Mutex.unlock();
cout << "存入的数据为" << i << endl;
}
}
void OutMsgRecvProc()
{
lock_guard<mutex> mutex_guard(Thread_Mutex);
//Thread_Mutex.lock();
if (!m_listMsgRecvQueue.empty())
{
int data = m_listMsgRecvQueue.front(); //从链表容器中取出数据
m_listMsgRecvQueue.pop_front(); //从链表头把数据进行删除
cout << "取出的数据为" << data << endl;
//Thread_Mutex.unlock();
}
else
{
cout << "目前队列为空" << endl;
//Thread_Mutex.unlock();
}
}
void OutMsgRecvQueue() //拿出数据线程
{
for (int i = 0; i < 10000; i++)
{
OutMsgRecvProc();
}
}
private:
list<int> m_listMsgRecvQueue; //链表容器
mutex Thread_Mutex; //保护数据所需的互斥锁
mutex Thread_Mutex1;
};
int main(void)
{
Thread_Test oThread_Test; //创建类对象
thread oOutMsgobj(&Thread_Test::OutMsgRecvQueue, &oThread_Test); //创建输出线程
thread oInMsgobj(&Thread_Test::InMsgRecvQueue, &oThread_Test); //创建输入线程
oOutMsgobj.join(); //主线程必须等待子线程结束
oInMsgobj.join();
return 0;
}