C++11多線程std::thread的簡單使用


轉自:http://blog.csdn.net/star530/article/details/24186783

在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沒有解鎖之前,其他使用這個互斥量加鎖的線程會一直處於等待狀態得不到執行


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM