C++多线程编程第十二讲--windows临界区、其他各种mutex互斥量

//(1)windows临界区
#include<iostream>
#include<thread>
#include<vector>
#include<list>
#include<mutex>

#include<windows.h>

#define _WINDOWS    //定义一个开关

using namespace std;

class A
{
public:
    A()
    {
#ifdef _WINDOWS
        InitializeCriticalSection(&my_winsec);    //用临界区之前要先初始化
#endif // _WINDOWS
    }

public:
    //把收到的消息,入到一个队列中
    void inMsgRecvQueue()
    {
        int i;
        for (i = 0; i < 100000; ++i)
        {
            cout << "push_back num = " << i << endl;
            //lock之后只能有一个线程可以对msgQueue队列做操作
#ifdef _WINDOWS
            EnterCriticalSection(&my_winsec);
            msgQueue.push_back(i);                   //数字i就是玩家的命令。
            LeaveCriticalSection(&my_winsec);
#else
            my_mutex.lock();
            msgQueue.push_back(i);                   //数字i就是玩家的命令。
            my_mutex.unlock();
#endif //        
        }
    }

    bool outMsgProc(int& command)
    {
#ifdef _WINDOWS
        EnterCriticalSection(&my_winsec);
        if (!msgQueue.empty())
        {
            //消息不为空
            command = msgQueue.front();
            msgQueue.pop_front();          //移除首元素

            LeaveCriticalSection(&my_winsec);
            return true;
        }
        else
        {
            LeaveCriticalSection(&my_winsec);
            return false;
        }
#else
        my_mutex.lock();
        if (!msgQueue.empty())
        {
            //消息不为空
            command = msgQueue.front();
            msgQueue.pop_front();          //移除首元素

            my_mutex.unlock();
            return true;
        }
        else
        {
            my_mutex.unlock();
            return false;
        }
#endif    
    }

    //把数据从消息队列中取出
    void outMsgRecvQueue()
    {
        int i;
        int command = 0;
        for (i = 0; i < 100000; ++i)
        {
            int result = outMsgProc(command);
            if (result == true)
            {
                cout << "command = " << command << endl;
            }
            else
            {
                cout << "msgQueue is empty" << endl;
            }
        }
    }

private:
    list<int> msgQueue;
    mutex my_mutex;       //创建一个互斥量
#ifdef _WINDOWS
    CRITICAL_SECTION my_winsec;     //windows下的临界区,非常类似C++的mutex
#endif // _WINDOES

};

int main()
{
    A myobj;

    thread myOutMsg(&A::outMsgRecvQueue, std::ref(myobj));   //保证线程中用的同一个对象
    thread myInMsg(&A::inMsgRecvQueue, std::ref(myobj));

    myOutMsg.join();
    myInMsg.join();

    cout << "main thread end..." << endl;
    return 0;
}

//(2)多次进入临界区试验

#include<iostream>
#include<thread>
#include<vector>
#include<list>
#include<mutex>

#include<windows.h>

#define _WINDOWS    //定义一个开关

using namespace std;

class A
{
public:
    A()
    {
#ifdef _WINDOWS
        InitializeCriticalSection(&my_winsec);    //用临界区之前要先初始化
#endif // _WINDOWS
    }

public:
    //把收到的消息,入到一个队列中
    void inMsgRecvQueue()
    {
        int i;
        for (i = 0; i < 100000; ++i)
        {
            cout << "push_back num = " << i << endl;
            //lock之后只能有一个线程可以对msgQueue队列做操作
#ifdef _WINDOWS
            EnterCriticalSection(&my_winsec);
            EnterCriticalSection(&my_winsec);     //这是允许的,但是对应的离开也需要写两次
            msgQueue.push_back(i);                   //数字i就是玩家的命令。
            LeaveCriticalSection(&my_winsec);
            LeaveCriticalSection(&my_winsec);     //如果这个没有的话,相当于还是一直加着锁。
#else
            my_mutex.lock();
            //my_mutex.lock();                        //会报错,和windows有区别
            msgQueue.push_back(i);                   //数字i就是玩家的命令。
            my_mutex.unlock();
#endif //        
        }
    }

    bool outMsgProc(int& command)
    {
#ifdef _WINDOWS
        EnterCriticalSection(&my_winsec);
        if (!msgQueue.empty())
        {
            //消息不为空
            command = msgQueue.front();
            msgQueue.pop_front();          //移除首元素

            LeaveCriticalSection(&my_winsec);
            return true;
        }
        else
        {
            LeaveCriticalSection(&my_winsec);
            return false;
        }
#else
        my_mutex.lock();
        if (!msgQueue.empty())
        {
            //消息不为空
            command = msgQueue.front();
            msgQueue.pop_front();          //移除首元素

            my_mutex.unlock();
            return true;
        }
        else
        {
            my_mutex.unlock();
            return false;
        }
#endif    
    }

    //把数据从消息队列中取出
    void outMsgRecvQueue()
    {
        int i;
        int command = 0;
        for (i = 0; i < 100000; ++i)
        {
            int result = outMsgProc(command);
            if (result == true)
            {
                cout << "command = " << command << endl;
            }
            else
            {
                cout << "msgQueue is empty" << endl;
            }
        }
    }

private:
    list<int> msgQueue;
    mutex my_mutex;       //创建一个互斥量
#ifdef _WINDOWS
    CRITICAL_SECTION my_winsec;     //windows下的临界区,非常类似C++的mutex
#endif // _WINDOES

};

int main()
{
    A myobj;

    thread myOutMsg(&A::outMsgRecvQueue, std::ref(myobj));   //保证线程中用的同一个对象
    thread myInMsg(&A::inMsgRecvQueue, std::ref(myobj));

    myOutMsg.join();
    myInMsg.join();

    cout << "main thread end..." << endl;
    return 0;
}

//(3)自动析构技术

// std::lock_guard<std::mutex>   //自动加锁和解锁

#include<iostream>
#include<thread>
#include<vector>
#include<list>
#include<mutex>

#include<windows.h>

#define _WINDOWS    //定义一个开关

using namespace std;

//自动加锁,自动释放锁的写法,类似与lock_guard的写法
class CWinLock
{
public:
    CWinLock(CRITICAL_SECTION* _my_winsec) :my_winsec(_my_winsec)
    {
        EnterCriticalSection(my_winsec);
    }

    ~CWinLock()
    {
        LeaveCriticalSection(my_winsec);
    }
private:
    CRITICAL_SECTION* my_winsec;     //windows下的临界区,非常类似C++的mutex
};

class A
{
public:
    A()
    {
#ifdef _WINDOWS
        InitializeCriticalSection(&my_winsec);    //用临界区之前要先初始化
#endif // _WINDOWS
    }

public:
    //把收到的消息,入到一个队列中
    void inMsgRecvQueue()
    {
        int i;
        for (i = 0; i < 100000; ++i)
        {
            cout << "push_back num = " << i << endl;
            //lock之后只能有一个线程可以对msgQueue队列做操作
#ifdef _WINDOWS
            CWinLock clock(&my_winsec);              //RAII的写法
            msgQueue.push_back(i);                   //数字i就是玩家的命令。

#else
            std::lock_guard<std::mutex> lock_g(my_mutex);   //自动加锁,自动释放锁。以{}为范围
            //my_mutex.lock();
            //my_mutex.lock();                        //会报错,和windows有区别
            msgQueue.push_back(i);                   //数字i就是玩家的命令。
            //my_mutex.unlock();
#endif //        
        }
    }

    bool outMsgProc(int& command)
    {
#ifdef _WINDOWS
        EnterCriticalSection(&my_winsec);
        if (!msgQueue.empty())
        {
            //消息不为空
            command = msgQueue.front();
            msgQueue.pop_front();          //移除首元素

            LeaveCriticalSection(&my_winsec);
            return true;
        }
        else
        {
            LeaveCriticalSection(&my_winsec);
            return false;
        }
#else
        my_mutex.lock();
        if (!msgQueue.empty())
        {
            //消息不为空
            command = msgQueue.front();
            msgQueue.pop_front();          //移除首元素

            my_mutex.unlock();
            return true;
        }
        else
        {
            my_mutex.unlock();
            return false;
        }
#endif    
    }

    //把数据从消息队列中取出
    void outMsgRecvQueue()
    {
        int i;
        int command = 0;
        for (i = 0; i < 100000; ++i)
        {
            int result = outMsgProc(command);
            if (result == true)
            {
                cout << "command = " << command << endl;
            }
            else
            {
                cout << "msgQueue is empty" << endl;
            }
        }
    }

private:
    list<int> msgQueue;
    mutex my_mutex;       //创建一个互斥量
#ifdef _WINDOWS
    CRITICAL_SECTION my_winsec;     //windows下的临界区,非常类似C++的mutex
#endif // _WINDOES

};

int main()
{
    A myobj;

    thread myOutMsg(&A::outMsgRecvQueue, std::ref(myobj));   //保证线程中用的同一个对象
    thread myInMsg(&A::inMsgRecvQueue, std::ref(myobj));

    myOutMsg.join();
    myInMsg.join();

    cout << "main thread end..." << endl;
    return 0;
}

//(4)recursive_mutex递归的独占互斥量

#include<iostream>
#include<thread>
#include<vector>
#include<list>
#include<mutex>

#include<windows.h>

//#define _WINDOWS    //定义一个开关

using namespace std;

//自动加锁,自动释放锁的写法,类似与lock_guard的写法
class CWinLock
{
public:
    CWinLock(CRITICAL_SECTION* _my_winsec) :my_winsec(_my_winsec)
    {
        EnterCriticalSection(my_winsec);
    }

    ~CWinLock()
    {
        LeaveCriticalSection(my_winsec);
    }
private:
    CRITICAL_SECTION* my_winsec;     //windows下的临界区,非常类似C++的mutex
};

class A
{
public:
    A()
    {
#ifdef _WINDOWS
        InitializeCriticalSection(&my_winsec);    //用临界区之前要先初始化
#endif // _WINDOWS
    }

public:
    //把收到的消息,入到一个队列中
    void inMsgRecvQueue()
    {
        int i;
        for (i = 0; i < 100000; ++i)
        {
            cout << "push_back num = " << i << endl;
            //lock之后只能有一个线程可以对msgQueue队列做操作
#ifdef _WINDOWS
            CWinLock clock(&my_winsec);              //RAII的写法
            msgQueue.push_back(i);                   //数字i就是玩家的命令。

#else
            my_mutex.lock();
            my_mutex.lock();                        //会报错,和windows有区别
            msgQueue.push_back(i);                   //数字i就是玩家的命令。
            my_mutex.unlock();
            my_mutex.unlock();
#endif //        
        }
    }

    bool outMsgProc(int& command)
    {
#ifdef _WINDOWS
        EnterCriticalSection(&my_winsec);
        if (!msgQueue.empty())
        {
            //消息不为空
            command = msgQueue.front();
            msgQueue.pop_front();          //移除首元素

            LeaveCriticalSection(&my_winsec);
            return true;
        }
        else
        {
            LeaveCriticalSection(&my_winsec);
            return false;
        }
#else
        my_mutex.lock();
        if (!msgQueue.empty())
        {
            //消息不为空
            command = msgQueue.front();
            msgQueue.pop_front();          //移除首元素

            my_mutex.unlock();
            return true;
        }
        else
        {
            my_mutex.unlock();
            return false;
        }
#endif    
    }

    //把数据从消息队列中取出
    void outMsgRecvQueue()
    {
        int i;
        int command = 0;
        for (i = 0; i < 100000; ++i)
        {
            int result = outMsgProc(command);
            if (result == true)
            {
                cout << "command = " << command << endl;
            }
            else
            {
                cout << "msgQueue is empty" << endl;
            }
        }
    }

private:
    list<int> msgQueue;
    //mutex my_mutex;       //创建一个互斥量,是一个独占互斥量
    //是一个递归的独占互斥量,在同一个线程内,可以多次lock,但也需要多次unlock,需要相对应
    recursive_mutex my_mutex;    //与windows中的CRITICAL_SECTION更像
#ifdef _WINDOWS
    CRITICAL_SECTION my_winsec;     //windows下的临界区,非常类似C++的mutex
#endif // _WINDOES

};

int main()
{
    A myobj;

    thread myOutMsg(&A::outMsgRecvQueue, std::ref(myobj));   //保证线程中用的同一个对象
    thread myInMsg(&A::inMsgRecvQueue, std::ref(myobj));

    myOutMsg.join();
    myInMsg.join();

    cout << "main thread end..." << endl;
    return 0;
}

//(5)带超时的互斥量std::timed_mutex和std::recursive_timed_mutex
    //try_lock_for()            //等待一段时间
    //try_lock_until()          //未来的时间点

#include<iostream>
#include<thread>
#include<vector>
#include<list>
#include<mutex>

#include<windows.h>

//#define _WINDOWS    //定义一个开关

using namespace std;

class A
{
public:
    A()
    {
#ifdef _WINDOWS
        InitializeCriticalSection(&my_winsec);    //用临界区之前要先初始化
#endif // _WINDOWS
    }

public:
    //把收到的消息,入到一个队列中
    void inMsgRecvQueue()
    {
        int i;
        for (i = 0; i < 100000; ++i)
        {
            cout << "push_back num = " << i << endl;
            //lock之后只能有一个线程可以对msgQueue队列做操作
#ifdef _WINDOWS
            CWinLock clock(&my_winsec);              //RAII的写法
            msgQueue.push_back(i);                   //数字i就是玩家的命令。
            
#else
            if (my_mutex.try_lock_until(chrono::steady_clock::now()+100ms))   //等待100ms来判断是否拿到锁
            {
                msgQueue.push_back(i);                   //数字i就是玩家的命令。

                my_mutex.unlock();
            }
            else
            {
                cout << "Do not get lock..." << endl;
            }
           
#endif //        
        }
    }

    bool outMsgProc(int& command)
    {
#ifdef _WINDOWS
        EnterCriticalSection(&my_winsec);
        if (!msgQueue.empty())
        {
            //消息不为空
            command = msgQueue.front();
            msgQueue.pop_front();          //移除首元素

            LeaveCriticalSection(&my_winsec);
            return true;
        }
        else
        {
            LeaveCriticalSection(&my_winsec);
            return false;
        }
#else
        my_mutex.lock();
        if (!msgQueue.empty())
        {
            //消息不为空
            command = msgQueue.front();
            msgQueue.pop_front();          //移除首元素

            my_mutex.unlock();
            return true;
    }
        else
        {
            my_mutex.unlock();
            return false;
        }
#endif    
    }

    //把数据从消息队列中取出
    void outMsgRecvQueue()
    {
        int i;
        int command = 0;
        for (i = 0; i < 100000; ++i)
        {
            int result = outMsgProc(command);
            if (result == true)
            {
                cout << "command = " << command << endl;
            }
            else
            {
                cout << "msgQueue is empty" << endl;
            }
        }
    }

private:
    list<int> msgQueue;
    std::timed_mutex my_mutex;
#ifdef _WINDOWS
    CRITICAL_SECTION my_winsec;     //windows下的临界区,非常类似C++的mutex
#endif // _WINDOES

};

int main()
{
    A myobj;

    thread myOutMsg(&A::outMsgRecvQueue, std::ref(myobj));   //保证线程中用的同一个对象
    thread myInMsg(&A::inMsgRecvQueue, std::ref(myobj));

    myOutMsg.join();
    myInMsg.join();

    cout << "main thread end..." << endl;
    return 0;
}

  

上一篇:进程同步与互斥习题


下一篇:优先级反转那点事