《1》windows临界区(稍微见识见识即可,因为不是linux下的,不是重点!)
因为windows临界区和C++11中的mutex互斥量非常类似,因此这里做个介绍。
demo_codes:
#include<iostream>
#include<mutex>
#include<thread>
#include<deque>
#include<Windows.h>
//若要在windows下自带的程序做一些多线程的编程工作,则必须要包含Windows.h这个头文件!
//用这个头文件编写的代码在linux下肯定是运行不了的!
using namespace std;
#define __WINDOWSJQ_
class A {
private:
#ifdef __WINDOWSJQ_
CRITICAL_SECTION my_winsec;//windows下的临界区变量,非常类似于c++11中的mutex!
#endif
std::mutex my_mutex;//创建一个互斥量
std::deque<int> msgRecvQueue;//队列容器,用来存放玩家给我们发送过来的命令!
public:
A() {
#ifdef __WINDOWSJQ_
InitializeCriticalSection(&my_winsec);//用临界区变量前必须给初始化!
#endif
}
//把收到的消息入到队列中的线程
void inMsgRecvQueue() {
for (int i = 0; i < 100000; i++) {
#ifdef __WINDOWSJQ_
EnterCriticalSection(&my_winsec);//进入临界区(加锁) ==> my_mutex.lock();
cout << "inMsgRecvQueue()执行,并插入一个元素:" << i << endl;
msgRecvQueue.push_back(i);
//假设这个数字i就是我所收到的命令!
LeaveCriticalSection(&my_winsec);//离开临界区(解锁) ==> my_mutex.unlock();
#else
my_mutex.lock();
cout << "inMsgRecvQueue()执行,并插入一个元素:" << i << endl;
msgRecvQueue.push_back(i);
//假设这个数字i就是我所收到的命令!
my_mutex.unlock();
#endif
}
}
bool outMsgLULProc(int& command) {
#ifdef __WINDOWSJQ_
EnterCriticalSection(&my_winsec);//进入临界区(加锁) ==> my_mutex.lock();
if (!msgRecvQueue.empty()) {
command = msgRecvQueue.front();
msgRecvQueue.pop_front();
LeaveCriticalSection(&my_winsec);//离开临界区(解锁) ==> my_mutex.unlock();
return true;
}
LeaveCriticalSection(&my_winsec);//离开临界区(解锁) ==> my_mutex.unlock();
#else
my_mutex.lock();
if (!msgRecvQueue.empty()) {
command = msgRecvQueue.front();
msgRecvQueue.pop_front();
my_mutex.unlock();
return true;
}
my_mutex.unlock();
#endif
return false;
}
void outMsgRecvQueue() {
int command = 0;
for (int i = 0; i < 100000; i++) {
bool res = outMsgLULProc(command);
if (res == true) {
cout << "outMsgRecvQueue()执行,取出一个命令元素:" << command << endl;
//这里可以考虑处理数据
//......
}else{
cout << "outMsgRecvQueue()执行,但目前队列为空,元素个数为0 i = " << i << endl;
}
}
cout << endl;
}
};
int main(void) {
A taobj;
std::thread myOutThread(&A::outMsgRecvQueue, std::ref(taobj));//注意这里的第2个参数必须是引用!才能够保证线程里不会再创建一个新的临时对象!
std::thread myInThread(&A::inMsgRecvQueue, std::ref(taobj));
myOutThread.join();
myInThread.join();
//让主线程等待这2个子线程都执行完毕后再汇合到主线程一起走!
return 0;
}
《2》多次进入临界区的试验(稍微见识见识即可,因为不是linux下的,不是重点!)
在“同一个线程”(不同线程中的锁,会卡住并等待其他线程中的锁解锁)中,windows中的“相同临界区变量”代表的临界区的进入(EnterCriticalSection)可以被多次调用!但是你调用了几次
EnterCriticalSection,你就得调用几次LeaveCriticalSection。
但是,在C++11的互斥量中,不允许在同一个线程入口函数中同一个互斥量调用.lock()或者.unlock()多次(2次及以上)!(当然,如果有某些条件判断语句可以提前结束该线程入口函数,那么此时就会存在多次调用.unlock()函数合理的情况!但本质上来说可认为还是调用了一次的!)
demo_codes:
#include<iostream>
#include<mutex>
#include<thread>
#include<deque>
#include<Windows.h>//若要在windows下做一些编程工作,则必须要包含windows.h这个 头文件!
//用这个头文件编写的代码在linux下肯定是运行不了的!
using namespace std;
//#define __WINDOWSJQ_
class A {
private:
#ifdef __WINDOWSJQ_
CRITICAL_SECTION my_winsec;//windows下的临界区变量,非常类似于c++11中的mutex!
#endif
std::mutex my_mutex;//创建一个互斥量
std::deque<int> msgRecvQueue;//队列容器,用来存放玩家给我们发送过来的命令!
public:
A() {
#ifdef __WINDOWSJQ_
InitializeCriticalSection(&my_winsec);//用临界区变量前必须给初始化!
#endif
}
//把收到的消息入到队列中的线程
void inMsgRecvQueue() {
for (int i = 0; i < 100000; i++) {
#ifdef __WINDOWSJQ_
EnterCriticalSection(&my_winsec);//==> my_mutex.lock();
EnterCriticalSection(&my_winsec);
cout << "inMsgRecvQueue()执行,并插入一个元素:" << i << endl;
msgRecvQueue.push_back(i);
//假设这个数字i就是我所收到的命令!
LeaveCriticalSection(&my_winsec);//==> my_mutex.unlock();
LeaveCriticalSection(&my_winsec);
#else
my_mutex.lock();
my_mutex.lock();//报告异常!与windows下的临界区变量不一样!
cout << "inMsgRecvQueue()执行,并插入一个元素:" << i << endl;
msgRecvQueue.push_back(i);
//假设这个数字i就是我所收到的命令!
my_mutex.unlock();
my_mutex.unlock();//报告异常!与windows下的临界区变量不一样!
#endif
}
}
bool outMsgLULProc(int& command) {
#ifdef __WINDOWSJQ_
EnterCriticalSection(&my_winsec);//==> my_mutex.lock();
EnterCriticalSection(&my_winsec);
if (!msgRecvQueue.empty()) {
command = msgRecvQueue.front();
msgRecvQueue.pop_front();
LeaveCriticalSection(&my_winsec);//==> my_mutex.unlock();
LeaveCriticalSection(&my_winsec);
return true;
}
LeaveCriticalSection(&my_winsec);//==> my_mutex.unlock();
LeaveCriticalSection(&my_winsec);
#else
my_mutex.lock();
if (!msgRecvQueue.empty()) {
command = msgRecvQueue.front();
msgRecvQueue.pop_front();
my_mutex.unlock();
return true;
}
my_mutex.unlock();
#endif
return false;
}
void outMsgRecvQueue() {
int command = 0;
for (int i = 0; i < 100000; i++) {
bool res = outMsgLULProc(command);
if (res == true) {
cout << "outMsgRecvQueue()执行,取出一个命令元素:" << command << endl;
//这里可以考虑处理数据
//......
}else{
cout << "outMsgRecvQueue()执行,但目前队列为空,元素个数为0 i = " << i << endl;
}
}
cout << endl;
}
};
int main(void) {
A taobj;
std::thread myOutThread(&A::outMsgRecvQueue, std::ref(taobj));//注意这里的第2个参数必须是引用!才能够保证线程里不会再创建一个新的临时对象!
std::thread myInThread(&A::inMsgRecvQueue, std::ref(taobj));
myOutThread.join();
myInThread.join();
//让主线程等待这2个子线程都执行完毕后再汇合到主线程一起走!
return 0;
}
运行结果:
demo2_codes:(在上述程序代码的基础上,把inMsgRecvQueue()函数修改为)
//把收到的消息入到队列中的线程
void inMsgRecvQueue() {
for (int i = 0; i < 100000; i++) {
#ifdef __WINDOWSJQ_
EnterCriticalSection(&my_winsec);//==> my_mutex.lock();
EnterCriticalSection(&my_winsec);
cout << "inMsgRecvQueue()执行,并插入一个元素:" << i << endl;
msgRecvQueue.push_back(i);
//假设这个数字i就是我所收到的命令!
LeaveCriticalSection(&my_winsec);//==> my_mutex.unlock();
LeaveCriticalSection(&my_winsec);
#else
//my_mutex.lock();
//my_mutex.lock();//报告异常!与windows下的临界区变量不一样!
std::lock_guard<std::mutex> sbguard(my_mutex);
std::lock_guard<std::mutex> sbguard2(my_mutex);
cout << "inMsgRecvQueue()执行,并插入一个元素:" << i << endl;
msgRecvQueue.push_back(i);
//假设这个数字i就是我所收到的命令!
//my_mutex.unlock();
//my_mutex.unlock();//报告异常!与windows下的临界区变量不一样!
#endif
}
}
运行结果:
即便你使用lock_guard这种自动给对应的互斥量加锁和解锁的类模板来do多次lock和unlock操作,结果仍然还是报告异常!因为该类模板的底层还是用的mutexObj.lock()和mutexObj.unlock()来实现的!
《3》自动析构技术
下面我们自己写一个类似与lock_guard的,且只用于windows下的自动enter(加锁)还有自动leave(解锁)临界区的类!
废话不多说,直接看代码进行学习:
#include<iostream>
#include<mutex>
#include<future>
#include<thread>
#include<deque>
#include<Windows.h>//若要在windows下做一些编程工作,则必须要包含windows.h这个 头文件!
//用这个头文件编写的代码在linux下肯定是运行不了的!
using namespace std;
#define __WINDOWSJQ_
//本类用于自动释放windows下的临界区,防止忘记LeaveCriticalSection导致死锁情况的发生
//这就类似于C++11中的std::lock_guard<std::mutex> 这个类模板的功能!
class CWinLock_guard {//这种类在有些书上叫做RAII类(Resource Acquisition is initialization)
//中文:资源获取即初始化
//容器、智能指针这些模板类都属于RAII类!以后有人和你玩这种名词时不要犯懵逼即可!
private:
CRITICAL_SECTION *m_pCritical;
public:
explicit CWinLock_guard(CRITICAL_SECTION *pCritical) :m_pCritical(pCritical) {
EnterCriticalSection(m_pCritical);//构造函数中初始化一个东西
}
~CWinLock_guard() noexcept {
LeaveCriticalSection(m_pCritical);//析构函数中释放一个东西
}
CWinLock_guard(const CWinLock_guard&) = delete;//不允许拷贝操作
CWinLock_guard& operator=(const CWinLock_guard&) = delete;//不允许赋值操作
};
//我自己照着lock_guard这个类模板的源码写了一个CLock_guard,功能和lock_guard一样!不信拿这段代码去下面测试一下即可!
//主要,要测试CLock_guard时应该把__WINDOWSJQ_注释掉!
template<typename _Mutex>
class CLock_guard {
private:
_Mutex& my_mutex;
public:
explicit CLock_guard(_Mutex& _Mtx) :my_mutex(_Mtx) {
my_mutex.lock();
}
~CLock_guard() noexcept {
my_mutex.unlock();
}
CLock_guard(const CLock_guard&) = delete;//不允许拷贝操作
CLock_guard& operator=(const CLock_guard&) = delete;//不允许赋值操作
};
class A {
private:
#ifdef __WINDOWSJQ_
CRITICAL_SECTION my_winsec;//windows下的临界区变量,非常类似于c++11中的mutex!
#endif
std::mutex my_mutex;//创建一个互斥量
std::deque<int> msgRecvQueue;//队列容器,用来存放玩家给我们发送过来的命令!
public:
A() {
#ifdef __WINDOWSJQ_
InitializeCriticalSection(&my_winsec);//用临界区变量前必须给初始化!
#endif
}
//把收到的消息入到队列中的线程
void inMsgRecvQueue() {
for (int i = 0; i < 100000; i++) {
#ifdef __WINDOWSJQ_
CWinLock_guard wlock1(&my_winsec);//没问题!正常运行!wlock1和wlock2都属于RAII类的对象!
CWinLock_guard wlock2(&my_winsec);
//EnterCriticalSection(&my_winsec);//==> my_mutex.lock();
//EnterCriticalSection(&my_winsec);
cout << "inMsgRecvQueue()执行,并插入一个元素:" << i << endl;
msgRecvQueue.push_back(i);
//假设这个数字i就是我所收到的命令!
//LeaveCriticalSection(&my_winsec);//==> my_mutex.unlock();
//LeaveCriticalSection(&my_winsec);
#else
//my_mutex.lock();
//my_mutex.lock();//报告异常!与windows下的临界区变量不一样!
//std::lock_guard<std::mutex> sbguard(my_mutex);
/* CLock_guard<std::mutex> sbguard(my_mutex);
CLock_guard<std::mutex> sbguard2(my_mutex);*/
std::lock_guard<std::mutex> sbguard2(my_mutex);
cout << "inMsgRecvQueue()执行,并插入一个元素:" << i << endl;
msgRecvQueue.push_back(i);
//假设这个数字i就是我所收到的命令!
//my_mutex.unlock();
//my_mutex.unlock();//报告异常!与windows下的临界区变量不一样!
#endif
}
}
bool outMsgLULProc(int& command) {
#ifdef __WINDOWSJQ_
EnterCriticalSection(&my_winsec);//==> my_mutex.lock();
EnterCriticalSection(&my_winsec);
if (!msgRecvQueue.empty()) {
command = msgRecvQueue.front();
msgRecvQueue.pop_front();
LeaveCriticalSection(&my_winsec);//==> my_mutex.unlock();
LeaveCriticalSection(&my_winsec);
return true;
}
LeaveCriticalSection(&my_winsec);//==> my_mutex.unlock();
LeaveCriticalSection(&my_winsec);
#else
my_mutex.lock();
if (!msgRecvQueue.empty()) {
command = msgRecvQueue.front();
msgRecvQueue.pop_front();
my_mutex.unlock();
return true;
}
my_mutex.unlock();
#endif
return false;
}
void outMsgRecvQueue() {
int command = 0;
for (int i = 0; i < 100000; i++) {
bool res = outMsgLULProc(command);
if (res == true) {
cout << "outMsgRecvQueue()执行,取出一个命令元素:" << command << endl;
//这里可以考虑处理数据
//......
}else{
cout << "outMsgRecvQueue()执行,但目前队列为空,元素个数为0 i = " << i << endl;
}
}
cout << endl;
}
};
int main(void) {
A taobj;
std::thread myOutThread(&A::outMsgRecvQueue, std::ref(taobj));//注意这里的第2个参数必须是引用!才能够保证线程里不会再创建一个新的临时对象!
std::thread myInThread(&A::inMsgRecvQueue, std::ref(taobj));
myOutThread.join();
myInThread.join();
//让主线程等待这2个子线程都执行完毕后再汇合到主线程一起走!
return 0;
}
好,上述就简要介绍这么多windows下的知识。下面继续总结C++11多线程的知识。
《4》std::recursive_mutex递归的独占互斥量
(类似于std::mutex,但是它有其独特的功能,即:允许在同一个线程中,同一个互斥量被.lock和.unlock多次!)
std::mutex 是独占式的互斥量。所谓独占式,即:当一个线程拿到锁头时,其他线程都拿不到锁了,必须在哪儿卡住等待该线程解锁才能竞争地去拿这把锁头!(简记为:自己lock时别人lock不了)
注意:互斥量都是独占式的!
recursive_mutex 是递归的独占互斥量。作用:允许在同一个线程中,同一个互斥量被.lock多次!
但是recursive_mutex 在使用效率上比mutex要差很多!因为很明显recursive_mutex 要比mutex做的工作多很多!
注意:当你在同一个线程入口函数中,需要同一个互斥量被.lock多次时,就必须要用std::recursive_mutex这种递归独占互斥量了!
demo_codes:
#include<iostream>
#include<mutex>
#include<thread>
#include<deque>
using namespace std;
class A {
private:
//std::mutex my_mutex;//创建一个独占式互斥量
std::recursive_mutex my_mutex;//创建一个递归独占式互斥量
std::deque<int> msgRecvQueue;//队列容器,用来存放玩家给我们发送过来的命令!
public:
//把收到的消息入到队列中的线程
void inMsgRecvQueue() {
for (int i = 0; i < 100000; i++) {
std::lock_guard<std::recursive_mutex> sbguard(my_mutex);
testfunc1();
cout << "inMsgRecvQueue()执行,并插入一个元素:" << i << endl;
msgRecvQueue.push_back(i);
//假设这个数字i就是我所收到的命令!
}
}
bool outMsgLULProc(int& command) {
my_mutex.lock();
if (!msgRecvQueue.empty()) {
command = msgRecvQueue.front();
msgRecvQueue.pop_front();
my_mutex.unlock();
return true;
}
my_mutex.unlock();
return false;
}
void testfunc1() {
std::lock_guard<std::recursive_mutex> sbguard(my_mutex);
//my_mutex.lock();
//干一些事情......
testfunc2();
//此时悲剧了!这样写你的程序必然会崩溃!因为testfunc2中也有锁!
//my_mutex.unlock();
}
void testfunc2() {
std::lock_guard<std::recursive_mutex> sbguard(my_mutex);
//my_mutex.lock();
//干另外一些事情......
//比如有3000行代码
//my_mutex.unlock();
}
void outMsgRecvQueue() {
int command = 0;
for (int i = 0; i < 100000; i++) {
bool res = outMsgLULProc(command);
if (res == true) {
cout << "outMsgRecvQueue()执行,取出一个命令元素:" << command << endl;
//这里可以考虑处理数据
//......
}else{
cout << "outMsgRecvQueue()执行,但目前队列为空,元素个数为0 i = " << i << endl;
}
}
cout << endl;
}
};
int main(void) {
A taobj;
std::thread myOutThread(&A::outMsgRecvQueue, std::ref(taobj));//注意这里的第2个参数必须是引用!才能够保证线程里不会再创建一个新的临时对象!
std::thread myInThread(&A::inMsgRecvQueue, std::ref(taobj));
myOutThread.join();
myInThread.join();
//让主线程等待这2个子线程都执行完毕后再汇合到主线程一起走!
return 0;
}
注意:一定要先行考虑你的多线程代码是否还有优化的空间,再去考虑用recursive_mutex这个互斥量在同一个线程入口函数中对于同一个该类型的互斥量进行多次的lock和unlock的事情!
《5》带超时功能的互斥量std::timed_mutex和std::recursive_timed_mutex
std::timed_mutex --> 是带超时功能的独占式互斥量
除了具备std::mutex的所有功能外,还具备2个新的成员函数:
1-.try_lock_for(时间值) 的参数是一个时间值。作用:让timed_mutex 这个互斥量等待一段时间后,若该互斥量拿到了锁头或者等待时间超过了规定时间还没拿到锁头时,就继续往下执行流程代码,不继续等了!
该成员函数的返回值为true时:表示该互斥量拿到了锁头或者等待时间超过了规定时间还没拿到锁头时,就继续往下执行流程代码,不继续等了!
返回值为false时:表示该互斥量根本就拿不到这个锁头,但也不会卡在这儿,还是会继续往下执行流程代码
该成员函数的返回值为true时:表示该互斥量拿到了锁头或者等待时间超过了规定地时间点还没拿到锁头时,就继续往下执行流程代码,不继续等了!
返回值为false时:表示该互斥量根本就拿不到这个锁头,但也不会卡在这儿,还是会继续往下执行流程代码
2-.try_lock_until(未来的时间点) 的参数是一个未来的时间点。作用:在我传入的这个未来的时间点参数没到来的这段时间内,如果该timed_mutex 互斥量拿到了锁头,代码继续走下来, 若未来的时间点到了还没有拿到锁头,代码还是会继续走下来,不会卡着!
std::recursive_timed_mutex --> 是带超时功能的递归独占式互斥量
与std::timed_mutex没大的区别,也都有try_lock_for()和try_lock_until()这2个成员函数,且功能一致。只不过它多了允许在同一个线程中对于同一个互斥量多次lock和unlock的功能而已!
所谓的超时功能:当一个互斥量拿不到锁时,不会“傻傻的”在这儿卡这等,而是继续往下去执行。
demo1_codes:
#include<iostream>
#include<mutex>
#include<thread>
#include<deque>
#include<chrono>
using namespace std;
class A {
private:
std::timed_mutex my_mutex;//创建一个带超时功能的独占式互斥量
std::deque<int> msgRecvQueue;//队列容器,用来存放玩家给我们发送过来的命令!
public:
//把收到的消息入到队列中的线程
void inMsgRecvQueue() {
for (int i = 0; i < 100000; i++) {
std::chrono::milliseconds timeout(100);//定义一个100ms的延迟
//my_mutex.try_lock_for(timeout) ==> my_mutex.try_lock_until(chrono::steady_clock::now() +timeout)
if (my_mutex.try_lock_until(chrono::steady_clock::now() +timeout)) {//表示从当前时间开始算,往后的100ms这样的一个时间点
//此时,就算在100ms之内拿到了锁头!
cout << "inMsgRecvQueue()执行,并插入一个元素:" << i << endl;
msgRecvQueue.push_back(i);
//假设这个数字i就是我所收到的命令!
//再do一些操作......
my_mutex.unlock();//记住!别忘记解锁了!
}
else {
//此时,就算是没有在100ms之内拿到锁头!
//此时我就让线程先休息100ms再继续执行for循环!
std::chrono::milliseconds sleeptime(100);
std::this_thread::sleep_for(sleeptime);
}
}
}
bool outMsgLULProc(int& command) {
my_mutex.lock();
/* std::chrono::seconds dura(200s);
std::this_thread::sleep_for(dura);*/
if (!msgRecvQueue.empty()) {
command = msgRecvQueue.front();
msgRecvQueue.pop_front();
my_mutex.unlock();
return true;
}
my_mutex.unlock();
return false;
}
void outMsgRecvQueue() {
int command = 0;
for (int i = 0; i < 100000; i++) {
bool res = outMsgLULProc(command);
if (res == true) {
cout << "outMsgRecvQueue()执行,取出一个命令元素:" << command << endl;
//这里可以考虑处理数据
//......
}else{
cout << "outMsgRecvQueue()执行,但目前队列为空,元素个数为0 i = " << i << endl;
}
}
cout << endl;
}
};
int main(void) {
A taobj;
std::thread myOutThread(&A::outMsgRecvQueue, std::ref(taobj));//注意这里的第2个参数必须是引用!才能够保证线程里不会再创建一个新的临时对象!
std::thread myInThread(&A::inMsgRecvQueue, std::ref(taobj));
myOutThread.join();
myInThread.join();
//让主线程等待这2个子线程都执行完毕后再汇合到主线程一起走!
//5-带超时的互斥量std::timed_mutex和std::recursive_timed_mutex;
//std::timed_mutex --> 是带超时功能的独占式互斥量
//std::recursive_timed_mutex --> 是带超时功能的递归独占式互斥量
return 0;
}
demo2_codes:
#include<iostream>
#include<mutex>
#include<thread>
#include<deque>
#include<chrono>
using namespace std;
class A {
private:
std::recursive_timed_mutex my_mutex;//创建一个带超时功能的递归独占式互斥量
std::deque<int> msgRecvQueue;//队列容器,用来存放玩家给我们发送过来的命令!
public:
//把收到的消息入到队列中的线程
void inMsgRecvQueue() {
for (int i = 0; i < 100000; i++) {
std::chrono::milliseconds timeout(100);//定义一个100ms的延迟
//my_mutex.try_lock_for(timeout) ==> my_mutex.try_lock_until(chrono::steady_clock::now() +timeout)
if (my_mutex.try_lock_until(chrono::steady_clock::now() +timeout)) {//表示从当前时间开始算,往后的100ms这样的一个时间点
//此时,就算在100ms之内拿到了锁头!
cout << "inMsgRecvQueue()执行,并插入一个元素:" << i << endl;
msgRecvQueue.push_back(i);
//假设这个数字i就是我所收到的命令!
//再do一些操作......
my_mutex.unlock();//记住!别忘记解锁了!
}
else {
//此时,就算是没有在100ms之内拿到锁头!
//此时我就让线程先休息100ms再继续执行for循环!
std::chrono::milliseconds sleeptime(100);
std::this_thread::sleep_for(sleeptime);
}
}
}
bool outMsgLULProc(int& command) {
my_mutex.lock();
/* std::chrono::seconds dura(200s);
std::this_thread::sleep_for(dura);*/
if (!msgRecvQueue.empty()) {
command = msgRecvQueue.front();
msgRecvQueue.pop_front();
my_mutex.unlock();
return true;
}
my_mutex.unlock();
return false;
}
void outMsgRecvQueue() {
int command = 0;
for (int i = 0; i < 100000; i++) {
bool res = outMsgLULProc(command);
if (res == true) {
cout << "outMsgRecvQueue()执行,取出一个命令元素:" << command << endl;
//这里可以考虑处理数据
//......
}else{
cout << "outMsgRecvQueue()执行,但目前队列为空,元素个数为0 i = " << i << endl;
}
}
cout << endl;
}
};
int main(void) {
A taobj;
std::thread myOutThread(&A::outMsgRecvQueue, std::ref(taobj));//注意这里的第2个参数必须是引用!才能够保证线程里不会再创建一个新的临时对象!
std::thread myInThread(&A::inMsgRecvQueue, std::ref(taobj));
myOutThread.join();
myInThread.join();
//让主线程等待这2个子线程都执行完毕后再汇合到主线程一起走!
//5-带超时的互斥量std::timed_mutex和std::recursive_timed_mutex;
//std::timed_mutex --> 是带超时功能的独占式互斥量
//std::recursive_timed_mutex --> 是带超时功能的递归独占式互斥量
return 0;
}
这2份测试代码都可以正常运行~