zoukankan      html  css  js  c++  java
  • C++11多线程std::thread的简单使用

    在cocos2dx 2.0时代,我们使用的是pthread库,是一套用户级线程库,被广泛地使用在跨平台应用上。但在cocos2dx 3.0中并未发现有pthread的支持文件,原来c++11中已经拥有了一个更好用的用于线程操作的类std::thread。cocos2dx 3.0的版本默认是在vs2012版本,支持c++11的新特性,使用std::thread来创建线程简直方便。

    下面介绍下std::thread的一下简单用法,代码需包含头文件<thread>

    bool HelloWorld::init()
    {
        if ( !Layer::init() )
        {
            return false;
        }
    
        std::thread t1(&HelloWorld::myThread,this);//创建一个分支线程,回调到myThread函数里
        t1.join();
    //    t1.detach();
    
    
        CCLOG("in major thread");//在主线程
    
    
        return true;
    }
    
    void HelloWorld::myThread()
    {
        CCLOG("in my thread");
    }

    运行结果如下图:
    这里写图片描述
    t.join()等待子线程myThread执行完之后,主线程才可以继续执行下去,此时主线程会释放掉执行完后的子线程资源。从上面的图片也可以看出,是先输出”in my thread”,再输出”in major thread”。
    当然了,如果不想等待子线程,可以在主线程里面执行t1.detach()将子线程从主线程里分离,子线程执行完成后会自己释放掉资源。分离后的线程,主线程将对它没有控制权了。如下:

    std::thread t1(&HelloWorld::myThread,this);//创建一个分支线程,回调到myThread函数里
    t1.detach();

    这里写图片描述
    当然了,也可以往线程函数里穿参数,这里用到了bind。下面例子在实例化线程对象的时候,在线程函数myThread后面紧接着传入两个参数。

    bool HelloWorld::init()
    {
        if ( !Layer::init() )
        {
            return false;
        }
    
        std::thread t1(&HelloWorld::myThread,this,10,20);//创建一个分支线程,回调到myThread函数里
        t1.join();
    //    t1.detach();
    
    
        CCLOG("in major thread");//在主线程
        return true;
    }
    
    
    void HelloWorld::myThread(int first,int second)
    {
        CCLOG("in my thread,first = %d,second = %d",first,second);
    }

    输出结果如下图:
    这里写图片描述
    实例:

    1.售票 孙鑫老师的C++和Java多线程售票也一直让我念念不忘(好吧,我承认我没看过),这里用cocos2d-x3.0和C++11的std::thread实现一个吧。总共有100张诺亚方舟船票,有2个售票点A和B在售票(一张票就一百亿美元吧),当票卖完了就结束了。我们知道当程序一开始进程就会创建一个主线程,所以可以在主线程基础上再创建2个线程A和B,再线程A和B中分别售票,当票数为0的时候,结束线程A和B。

    2.多线程售票,代码如下:

    //HelloWorld.h
    class HelloWorld : public cocos2d::Layer
    {
    public:
        static cocos2d::Scene* createScene();
        virtual bool init();  
    
        CREATE_FUNC(HelloWorld);
    
        void myThreadA();//线程A
        void myThreadB();//线程B
    
        int tickets;//票数  
    
    };
    
    //.cpp
    bool HelloWorld::init()
    {
        if ( !Layer::init() )
        {
            return false;
        }
    
        tickets = 100;//100张票
    
        std::thread tA(&HelloWorld::myThreadA,this);//创建一个分支线程,回调到myThread函数里
        std::thread tB(&HelloWorld::myThreadB,this);
        tA.detach();
        tB.detach();
    //    t1.detach();
    
        CCLOG("in major thread");//在主线程
        return true;
    }
    
    void HelloWorld::myThreadA()
    {
        while(true)  
        {  
            if(tickets>0)  
            {  
                Sleep(10);
                CCLOG("A Sell %d",tickets--);//输出售票,每次减1  
            }  
            else {  
                break;  
            }  
        }  
    }
    void HelloWorld::myThreadB()
    {
        while(true)  
        {  
            if (tickets>0)  
            {  
                Sleep(10);
                CCLOG("B Sell %d",tickets--);  
            }  
            else   
            {  
                break;  
            }  
        }  
    }

    代码很简单,不多说了。我们来看一下输出,会发现有很多喜闻乐见的现象出现,因为每个人每次运行的结果都不一样,所以这里不贴结果了,其中比较有意思的现象是同一张票卖了两次?!
    原因不多解释了,时间片的问题,不明白的Google之。如果你觉得不会有这么巧,那么在打印结果前加上这么一句:

    Sleep(100);

    这里写图片描述
    3.利用互斥对象同步数据
    这个问题主要是因为一个线程执行到一半的时候,时间片的切换导致另一个线程修改了同一个数据,当再次切换会原来线程并继续往下运行的时候,数据由于被修改了导致结果出错。所以我们要做的就是保证这个线程完全执行完,所以对线程加锁是个不错的注意,互斥对象mutex就是这个锁。
    3.1、初始化互斥锁

    std::mutex mutex;//线程互斥对象

    3.2、修改myThreadA与myThreadB的代码,在里面添加互斥锁

    void HelloWorld::myThreadA()
    {
        while(true)  
        {  
            mutex.lock();//加锁
            if(tickets>0)  
            {  
                Sleep(10);
                CCLOG("A Sell %d",tickets--);//输出售票,每次减1  
                mutex.unlock();//解锁
            }  
            else {  
                mutex.unlock();
                break;  
    
            }  
        }  
    }
    void HelloWorld::myThreadB()
    {
        while(true)  
        {  
            mutex.lock();
            if (tickets>0)  
            {  
                Sleep(10);
                CCLOG("B Sell %d",tickets--);  
                mutex.unlock();
            }  
            else   
            {  
                mutex.unlock();
                break;              
            }  
        }  
    }

    运行结果如下,完美
    这里写图片描述
    使用std::mutex有一个要注意的地方:在线程A中std::mutex使用成员函数lock加锁unlock解锁,看起来工作的很好,但这样是不安全的,你得始终记住lock之后一定要unlock,但是如果在它们中间出现了异常或者线程直接退出了unlock就没有执行,因为这个互斥量是独占式的,所以在threadA没有解锁之前,其他使用这个互斥量加锁的线程会一直处于等待状态得不到执行

  • 相关阅读:
    Unix命令大全
    vs2008 与 IE8出现的兼容性问题
    Java 创建文件、文件夹以及临时文件
    如何修改Wamp中mysql默认空密码
    PAT 乙级真题 1003.数素数
    Tags support in htmlText flash as3
    DelphiXE4 FireMonkey 试玩记录,开发IOS应用 还是移植
    10 Great iphone App Review sites to Promote your Apps!
    HTML tags in textfield
    Delphi XE4 IOS 开发, "No eligible applications were found“
  • 原文地址:https://www.cnblogs.com/laohaozi/p/12538121.html
Copyright © 2011-2022 走看看