C++并行开发12-windows临界区、其他各种mutex互斥量
windows临界区使用
#include <iostream>
#include <thread>
#include <algorithm>
#include <vector>
#include <list>
#include <mutex>
#include <windows.h>
using namespace std;
#define __WINDOWSJQ
//调用类对象的成员函数的方式来创建线程
class A {
public:
void inMsgRecvQueue()
{
for (int i = 0; i < 10000; i++) {
#ifdef __WINDOWSJQ
EnterCriticalSection(&my_winsec); //相当于拿到锁
cout << "消息队列插入一个元素 " << i << endl;
msgRecvQueue.push_back(i);
LeaveCriticalSection(&my_winsec);
#else
my_mutex.lock();
cout << "消息队列插入一个元素 " << i << endl;
msgRecvQueue.push_back(i);
my_mutex.unlock();
#endif
}
}
bool judgeOutMsg(int &command) {
#ifdef __WINDOWSJQ
EnterCriticalSection(&my_winsec); //相当于拿到锁
if (!msgRecvQueue.empty()) {
//消息队列非空
command = msgRecvQueue.front(); //取出第一个元素
msgRecvQueue.pop_front();
LeaveCriticalSection(&my_winsec);
return true;
}
else {
LeaveCriticalSection(&my_winsec);
return false;
}
#else
my_mutex.lock();
if (!msgRecvQueue.empty()) {
//消息队列非空
command = msgRecvQueue.front(); //取出第一个元素
msgRecvQueue.pop_front();
my_mutex.unlock(); //这个unlock不能忘
return true;
}
else {
my_mutex.unlock();
return false;
}
#endif
}
void outMsgRecgQueue() {
int commond = 0;
for (int i = 0; i < 10000; i++) {
bool result = judgeOutMsg(commond);
if (result) {
cout << "消息队列中取出了一个元素" << commond << endl;
}
else {
cout << "消息队列为空" << endl;
}
}
}
A() {
#ifdef __WINDOWSJQ
InitializeCriticalSection(&my_winsec);
#endif
}
private:
list<int> msgRecvQueue; //消息队列
std::mutex my_mutex;// 创建一个互斥量
#ifdef __WINDOWSJQ
CRITICAL_SECTION my_winsec; //类似于C++11中的mutex
#endif
};
int main()
{
A myobja;
std::thread myOutnMsgObj(&A::outMsgRecgQueue, &myobja);
std::thread myInnMsgObj(&A::inMsgRecvQueue, &myobja);
//这里必须使用引用,否则线程会重新拷贝构造一个对象,
//但是使用引用就需要考虑类对象的使用周期,必须在主线程使用结束
myOutnMsgObj.join();
myInnMsgObj.join();
//保护共享数据,操作时候用代码将共享数据锁住,其他想操作共享数据的线程必须等待解锁
//(一) mutex的基本概念
// lock unlock 应该成对出现
return 0;
}
上述的EnterCriticalSection(&my_winsec);相当于拿到锁头,
LeaveCriticalSection(&my_winsec);相当于解锁
在同一个线程中,EnterCriticalSection(&my_winsec);可以同时进入多次,但是LeaveCriticalSection(&my_winsec)次数要保持一致
而在C++11中不允许lock多次
自动析构技术
#include <iostream>
#include <thread>
#include <algorithm>
#include <vector>
#include <list>
#include <mutex>
#include <windows.h>
using namespace std;
#define __WINDOWSJQ
class CWinLock { //RAII类
public:
CWinLock(CRITICAL_SECTION *pCritical) {
m_pCritical = pCritical;
EnterCriticalSection(m_pCritical);
}
~CWinLock() {
LeaveCriticalSection(m_pCritical);
}
private:
CRITICAL_SECTION *m_pCritical; //类似于C++11中的mutex
};
//调用类对象的成员函数的方式来创建线程
class A {
public:
void inMsgRecvQueue()
{
for (int i = 0; i < 10000; i++) {
#ifdef __WINDOWSJQ
//EnterCriticalSection(&my_winsec); //相当于拿到锁
CWinLock winLock(&my_winsec);
cout << "消息队列插入一个元素 " << i << endl;
msgRecvQueue.push_back(i);
//LeaveCriticalSection(&my_winsec);
#else
my_mutex.lock();
cout << "消息队列插入一个元素 " << i << endl;
msgRecvQueue.push_back(i);
my_mutex.unlock();
#endif
}
}
bool judgeOutMsg(int &command) {
#ifdef __WINDOWSJQ
EnterCriticalSection(&my_winsec); //相当于拿到锁
if (!msgRecvQueue.empty()) {
//消息队列非空
command = msgRecvQueue.front(); //取出第一个元素
msgRecvQueue.pop_front();
LeaveCriticalSection(&my_winsec);
return true;
}
else {
LeaveCriticalSection(&my_winsec);
return false;
}
#else
my_mutex.lock();
if (!msgRecvQueue.empty()) {
//消息队列非空
command = msgRecvQueue.front(); //取出第一个元素
msgRecvQueue.pop_front();
my_mutex.unlock(); //这个unlock不能忘
return true;
}
else {
my_mutex.unlock();
return false;
}
#endif
}
void outMsgRecgQueue() {
int commond = 0;
for (int i = 0; i < 10000; i++) {
bool result = judgeOutMsg(commond);
if (result) {
cout << "消息队列中取出了一个元素" << commond << endl;
}
else {
cout << "消息队列为空" << endl;
}
}
}
A() {
#ifdef __WINDOWSJQ
InitializeCriticalSection(&my_winsec);
#endif
}
private:
list<int> msgRecvQueue; //消息队列
std::mutex my_mutex;// 创建一个互斥量
#ifdef __WINDOWSJQ
CRITICAL_SECTION my_winsec; //类似于C++11中的mutex
#endif
};
int main()
{
A myobja;
std::thread myOutnMsgObj(&A::outMsgRecgQueue, &myobja);
std::thread myInnMsgObj(&A::inMsgRecvQueue, &myobja);
//这里必须使用引用,否则线程会重新拷贝构造一个对象,
//但是使用引用就需要考虑类对象的使用周期,必须在主线程使用结束
myOutnMsgObj.join();
myInnMsgObj.join();
//保护共享数据,操作时候用代码将共享数据锁住,其他想操作共享数据的线程必须等待解锁
//(一) mutex的基本概念
// lock unlock 应该成对出现
return 0;
}
通过构造一个RAII类,自动释放析构临界区
recursive_mutex
//std::mutex my_mutex;// 创建一个互斥量
std::recursive_mutex my_mutex;
std::recursive_mutex递归的独占互斥量,可以多次lock unlock recursive_mutex效率比mutex效率低
timed_mutex
#include <iostream>
#include <thread>
#include <algorithm>
#include <vector>
#include <list>
#include <mutex>
#include <windows.h>
using namespace std;
//#define __WINDOWSJQ
class CWinLock { //RAII类
public:
CWinLock(CRITICAL_SECTION *pCritical) {
m_pCritical = pCritical;
EnterCriticalSection(m_pCritical);
}
~CWinLock() {
LeaveCriticalSection(m_pCritical);
}
private:
CRITICAL_SECTION *m_pCritical; //类似于C++11中的mutex
};
//调用类对象的成员函数的方式来创建线程
class A {
public:
void inMsgRecvQueue()
{
for (int i = 0; i < 10000; i++) {
#ifdef __WINDOWSJQ
//EnterCriticalSection(&my_winsec); //相当于拿到锁
CWinLock winLock(&my_winsec);
cout << "消息队列插入一个元素 " << i << endl;
msgRecvQueue.push_back(i);
//LeaveCriticalSection(&my_winsec);
#else
std::chrono::milliseconds timeout(100);
if (my_mutex.try_lock_for(timeout)) { //等待100ms来尝试获取锁
//if成立拿到锁
msgRecvQueue.push_back(i);
my_mutex.unlock();
}
else {
//这次没有拿到锁头
cout << "没有拿到锁头" << endl;
std::chrono::milliseconds sleeptime(100);
std::this_thread::sleep_for(sleeptime);
}
//my_mutex.lock();
//cout << "消息队列插入一个元素 " << i << endl;
//msgRecvQueue.push_back(i);
//my_mutex.unlock();
#endif
}
}
bool judgeOutMsg(int &command) {
#ifdef __WINDOWSJQ
EnterCriticalSection(&my_winsec); //相当于拿到锁
if (!msgRecvQueue.empty()) {
//消息队列非空
command = msgRecvQueue.front(); //取出第一个元素
msgRecvQueue.pop_front();
LeaveCriticalSection(&my_winsec);
return true;
}
else {
LeaveCriticalSection(&my_winsec);
return false;
}
#else
my_mutex.lock();
std::chrono::milliseconds sleeptime(1000); //测试拿到锁,但是没有释放
std::this_thread::sleep_for(sleeptime);
if (!msgRecvQueue.empty()) {
//消息队列非空
command = msgRecvQueue.front(); //取出第一个元素
msgRecvQueue.pop_front();
my_mutex.unlock(); //这个unlock不能忘
return true;
}
else {
my_mutex.unlock();
return false;
}
#endif
}
void outMsgRecgQueue() {
int commond = 0;
for (int i = 0; i < 10000; i++) {
bool result = judgeOutMsg(commond);
if (result) {
cout << "消息队列中取出了一个元素" << commond << endl;
}
else {
cout << "消息队列为空" << endl;
}
}
}
A() {
#ifdef __WINDOWSJQ
InitializeCriticalSection(&my_winsec);
#endif
}
private:
list<int> msgRecvQueue; //消息队列
//std::mutex my_mutex;// 创建一个互斥量
//std::recursive_mutex my_mutex;
std::timed_mutex my_mutex; //带超时功能的互斥量
#ifdef __WINDOWSJQ
CRITICAL_SECTION my_winsec; //类似于C++11中的mutex
#endif
};
int main()
{
A myobja;
std::thread myOutnMsgObj(&A::outMsgRecgQueue, &myobja);
std::thread myInnMsgObj(&A::inMsgRecvQueue, &myobja);
//这里必须使用引用,否则线程会重新拷贝构造一个对象,
//但是使用引用就需要考虑类对象的使用周期,必须在主线程使用结束
myOutnMsgObj.join();
myInnMsgObj.join();
// std::recursive_mutex递归的独占互斥量,可以多次lock unlock
// recursive_mutex效率比mutex效率低
//
//std::timed_mutex: 带超时功能的独占互斥量
// try_lock_for(): 等待一段时间,如果没有拿到锁头,流程就要往下走
//std::recursive_timed_mutex: 带超时功能的递归独占互斥量
return 0;
}
try_lock_until和try_lock_for功能类似,只是相当于一个未来的时间
//if (my_mutex.try_lock_for(timeout)) { //等待100ms来尝试获取锁
// //if成立拿到锁
// msgRecvQueue.push_back(i);
// my_mutex.unlock();
//}
if (my_mutex.try_lock_until(chrono::steady_clock::now() + timeout)) { //等待100ms来尝试获取锁
//if成立拿到锁
msgRecvQueue.push_back(i);
my_mutex.unlock();
}
- Title: C++并行开发12-windows临界区、其他各种mutex互斥量
- Author: FengLY
- Created at : 2023-06-18 22:40:09
- Updated at : 2023-06-18 22:59:30
- Link: https://zhouaq.com/2023/06/18/C++并行开发12-windows临界区、其他各种mutex互斥量/
- License: This work is licensed under CC BY-NC-SA 4.0.
Comments