欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

windows临界区

程序员文章站 2022-07-05 10:59:00
...

windows临界区

像下面这种编程是针对于C++语言本身的,是可以跨平台的

windows临界区和C++的mutex非常类似

现在讲讲windows下一些专用的术语,跟互斥量的关联

下面是一段用互斥量来演示的代码

class A
{
public: 
    //把收到的消息(玩家命令)放入到一个队列的线程
    void inMsgRecvQueue()
    {
        for(int i = 0; i < 100000; ++i )//如果整个循环都lock,那其他线程不用玩了,循环100000次
        {
            cout << "inMsgRecvQueue()执行,插入一个元素" << i << endl;
            //我们只给操作共享数据的内容加锁
            my_mutex.lock();
           msgRecvQueue.push_back(i);//假设这个数字i就是我们收到的命令,我直接弄到消息队列里边来,跑完这个循环这就等于收集了100000个玩家的命令
            my_mutex.unlock();
        }
        return;
    }
    //把数据从消息队列中取出的线程
    bool outMsgLULProc(int num)
    {
        my_mutex.lock();
         if(!msgRecvQueue.empty())//空不空的判断也是属于读共享数据,所以也加锁
            {
                //不为空
                int command = msgMsgRecvQueue.front(); //返回第一个元素,但不检查元素是否存在;我们在前面empty()已经判断过,所以问题不大
                msgRecvQueue.pop_front();//拿过之后就要把第一个移除,不然一直拿都是这个
             my_mutex.unlock();//这个unlock和下面的unlock不会同时执行,所以还是一个unlock与上面一个lock配对,不冲突
             
             //要注意这种情况
             ///
               return true;
            }
         my_mutex.unlock();
        return false;
	}
    
    void outMsgRecvQueue()
    {
        int command = 0;
        for(int i = 0; i < 100000; ++i )
        {
            bool result = outMsgLULProc(command);
            if(result == true)
            {
                cout << "outMsgRecvQueue()执行,取出一个元素" << command << endl;
                //可以考虑进行命令(数据)处理
            }
            else{
                //消息队列为空
                cout << "outMsgRecvQueue()执行,但目前消息队列中为空 " << i << endl;
            }
        }
        cout << "end" << endl;
    }
private:
    std::list<int> msgRecvQueue;//容器(消息队列),专门用于代表玩家给咱们发送过来的命令(共享数据)
    std::mutex my_mutex;///创建了一个互斥量
    
    
};

int main()
{
    A myobja;
    //创建取命令的线程
    std::thread myOutnMsgObj(&A::outMsgRecvQueue, &myobja);//第二个参数是引用,这样才能保证主线程和子线程都是用同一个对象
    //创建放命令线程
    std::thread myInMsgObj(&A::inMsgRecvQueue, &myobja);//两个线程用同一个对象,所以他们可以消息互通
    //这两个join谁先谁后问题不大
    myOutnMsgObj.join();
    myInMsgObj.join();
}

写windows临界区要包含一个特定的头文件 #include <windows.h>,改成用windows的临界区

//定义一个开关,如果这个开关打开就执行windows下的代码,如果关闭就执行C++11原有的代码
#define __WINDOWSJQ_

class A
{
public: 
    //把收到的消息(玩家命令)放入到一个队列的线程
    void inMsgRecvQueue()
    {
        for(int i = 0; i < 100000; ++i )//如果整个循环都lock,那其他线程不用玩了,循环100000次
        {
            cout << "inMsgRecvQueue()执行,插入一个元素" << i << endl;
 #ifdef __WINDOWSJQ_
   			EnterCriticalSection(&my_winsec);//进入临界区
             msgRecvQueue.push_back(i);
            LeaveCriticalSection(&my_winsec);//离开临界区
 #else    
            
            //我们只给操作共享数据的内容加锁
            my_mutex.lock();
           msgRecvQueue.push_back(i);//假设这个数字i就是我们收到的命令,我直接弄到消息队列里边来,跑完这个循环这就等于收集了100000个玩家的命令
            my_mutex.unlock();
  #endif
        }
        return;
    }
    //把数据从消息队列中取出的线程
    bool outMsgLULProc(int num)
    {
#ifdef __WINDOWSJQ_
   			EnterCriticalSection(&my_winsec);//进入临界区
             if(!msgRecvQueue.empty())//空不空的判断也是属于读共享数据,所以也加锁
            {
                //不为空
                int command = msgMsgRecvQueue.front(); //返回第一个元素,但不检查元素是否存在;我们在前面empty()已经判断过,所以问题不大
                msgRecvQueue.pop_front();//拿过之后就要把第一个移除,不然一直拿都是这个
             LeaveCriticalSection(&my_winsec);//离开临界区
               return true;
            }
            LeaveCriticalSection(&my_winsec);//离开临界区
 #else  
        my_mutex.lock();
         if(!msgRecvQueue.empty())//空不空的判断也是属于读共享数据,所以也加锁
            {
                //不为空
                int command = msgMsgRecvQueue.front(); //返回第一个元素,但不检查元素是否存在;我们在前面empty()已经判断过,所以问题不大
                msgRecvQueue.pop_front();//拿过之后就要把第一个移除,不然一直拿都是这个
             my_mutex.unlock();//这个unlock和下面的unlock不会同时执行,所以还是一个unlock与上面一个lock配对,不冲突
             
             //要注意这种情况
             ///
               return true;
            }
         my_mutex.unlock();
   #endif      
        return false;
	}
    
    void outMsgRecvQueue()
    {
        int command = 0;
        for(int i = 0; i < 100000; ++i )
        {
            bool result = outMsgLULProc(command);
            if(result == true)
            {
                cout << "outMsgRecvQueue()执行,取出一个元素" << command << endl;
                //可以考虑进行命令(数据)处理
            }
            else{
                //消息队列为空
                cout << "outMsgRecvQueue()执行,但目前消息队列中为空 " << 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中的mutex
   #endif   

};

int main()
{
    A myobja;
    //创建取命令的线程
    std::thread myOutnMsgObj(&A::outMsgRecvQueue, &myobja);//第二个参数是引用,这样才能保证主线程和子线程都是用同一个对象
    //创建放命令线程
    std::thread myInMsgObj(&A::inMsgRecvQueue, &myobja);//两个线程用同一个对象,所以他们可以消息互通
    //这两个join谁先谁后问题不大
    myOutnMsgObj.join();
    myInMsgObj.join();
}