C++并行开发12-windows临界区、其他各种mutex互斥量

FengLY Lv3

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
On this page
C++并行开发12-windows临界区、其他各种mutex互斥量