Windows临界区与互斥量用法非常相似;但也有些差别
在“同一个线程”(不同线程中会卡住等待)中, Windows中的“相同临界区变量”代表的临界区的进入(EnterCriticalSection)可以被多次调用,但是调用了几次EnterCriticalSection(),就得调用几次EnterCriticalSection()
而在C++11中,std::mutex不允许同一个线程中lock同一个互斥量多次,否则报异常;
多线程 互斥量与Windows临界区对比代码如下:
#define _WINDOWSJQ_
class A
{
public:
//把收到的消息入到一个队列的线程
void inMsgRecvQueue()
{
for (int i = 0; i < 10000; i++)
{
cout << "inMsgRecvQueue()执行,插入一个元素" << i << endl;
#ifdef _WINDOWSJQ_
EnterCriticalSection(&my_winsec); //进入临界区(加锁)
msgRecvQueue.push_back(i);
LeaveCriticalSection(&my_winsec); //离开临界区(解锁)
#else
std::lock_guard<std::mutex> sbguard(my_mutex);
msgRecvQueue.push_back(i); //假设这个数字i就是收到的命令,直接弄到消息队列里边来;
#endif
}
}
bool outMsgLULProc(int &command)
{
#ifdef _WINDOWSJQ_
EnterCriticalSection(&my_winsec);
if (!msgRecvQueue.empty())
{
//消息不为空
int command = msgRecvQueue.front();//返回第一个元素,但不检查元素是否存在
msgRecvQueue.pop_front();//移除第一个元素。但不返回;
LeaveCriticalSection(&my_winsec);
return true;
}
LeaveCriticalSection(&my_winsec);
#else
my_mutex.lock();
if (!msgRecvQueue.empty())
{
//消息不为空
int command = msgRecvQueue.front();//返回第一个元素,但不检查元素是否存在
msgRecvQueue.pop_front();//移除第一个元素。但不返回;
my_mutex.unlock(); //所有分支都必须有unlock()
return true;
}
my_mutex.unlock();
#endif
return false;
}
//把数据从消息队列取出的线程
void outMsgRecvQueue()
{
int command = 0;
for (int i = 0; i < 10000; i++)
{
bool result = outMsgLULProc(command);
if (result == true)
{
cout << "outMsgRecvQueue()执行,取出一个元素" << endl;
//处理数据
}
else
{
//消息队列为空
cout << "inMsgRecvQueue()执行,但目前消息队列中为空!" << i << endl;
}
}
cout << "end!" << endl;
}
A()
{
#ifdef _WINDOWSJQ_
InitializeCriticalSection(&my_winsec);//用临界区之前先初始化
#endif
}
private:
std::list<int> msgRecvQueue;//容器(消息队列),代表玩家发送过来的命令。
std::mutex my_mutex;//创建一个互斥量(一把锁)
#ifdef _WINDOWSJQ_
CRITICAL_SECTION my_winsec; //windows中的临界区,非常类似C++11中的互斥量
#endif
};
2.其他mutex互斥量
2.1 recursive_mutex递归的独占互斥量
recursive_mutex 递归的独占互斥量:允许同一个线程,同一个互斥量多次被lock,但效率上比mutex更低;递归次数据说有限制,递归太多可能有异常。
2.2超时互斥量std::timed_mutex
std:: timed_mutex:带超时功能的独占互斥量
try_lock_for():等待一段时间,如果拿到了锁,或者等待超时,没有拿到锁,就走下来
try_lock_until();参数是一个未来的时间点,这个未来的时间没到的时间内,如果我拿到了锁头,那么就走下来;如果时间到了,没拿到锁,程序的流程也走下来;
timed_mutex myMutex;
chrono::milliseconds timeout(100); //100毫秒
if (myMutex.try_lock_for(timeout))
{
//在100毫秒内获取了锁
//业务代码
myMutex.unlock(); //释放锁
}
else
{
//在100毫秒内没有获取锁
//业务代码
}
2.3超时递归互斥量recursive_timed_mutex
std:: recursive_timed_mutex:带超时功能的递归独占互斥量(允许同一个线程多次获取这互斥量),用法与std::timed_mutex相同。
3.自动析构技术
智能指针是如何实现自动析构的,以前面试中被问过这个问题,其实实现方法很简单,不解释了,直接给例子:
//本类用于自动释放windows下的临界区,防止忘记LeaveCriticalSection导致死锁的情况发生,
//类似于C++11中的std::lock_guard<std::mutex>
class CWinLock //叫RAII类 (resource Acquisition is initialization)“资源获取即初始化” eg 智能指针类,容器 都属于RAII类
{
public:
CWinLock(CRITICAL_SECTION *pCritmp)
{
m_Pcitical = pCritmp;
EnterCriticalSection(m_Pcitical);
}
~CWinLock()
{
LeaveCriticalSection(m_Pcitical);
}
private:
CRITICAL_SECTION *m_Pcitical;
};