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

在cocos2dx 2.0時代,咱們使用的是pthread庫,是一套用戶級線程庫,被普遍地使用在跨平臺應用上。但在cocos2dx 3.0中並未發現有pthread的支持文件,原來c++11中已經擁有了一個更好用的用於線程操做的類std::thread。cocos2dx 3.0的版本默認是在vs2012版本,支持c++11的新特性,使用std::thread來建立線程簡直方便。c++

下面介紹下std::thread的一下簡單用法安全

 #inlcude<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()將子線程從主線程裏分離,子線程執行完成後會本身釋放掉資源。分離後的線程,主線程將對它沒有控制權了。以下:this

std::thread t1(&HelloWorld::myThread,this);//建立一個分支線程,回調到myThread函數裏t1.detach();

運行結果以下:spa

 

固然了,也能夠往線程函數裏穿參數,這裏用到了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){    C
  CLOG("in my thread,first = %d,second = %d",first,second);
}

輸出結果以下圖:c++11

 

 

實例:對象

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.一、初始化互斥鎖

std::mutex mutex;//線程互斥對象

3.二、修改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沒有解鎖以前,其餘使用這個互斥量加鎖的線程會一直處於等待狀態得不到執行

相關文章
相關標籤/搜索