【玩轉cocos2d-x之二十二】多執行緒和同步02-售票
阿新 • • 發佈:2019-01-04
pthread有很多不同應用,官網都有相應的API解釋和Sample,這裡不再重複,本文主要介紹一個cocos2d-x多執行緒和同步示例。
1.售票
孫鑫老師的C++和Java多執行緒售票一直讓我念念不忘,好吧,這裡用cocos2d-x和pthread實現一個吧。總共有100張火車票,有2個售票點A和B再售票,當票賣完了就結束了。我們知道當程式一開始程序就會建立一個主執行緒,所以可以在主執行緒基礎上再建立2個執行緒A和B,再執行緒A和B中分別售票,當票數為0的時候,結束執行緒A和B。
2.多執行緒售票
程式碼很簡單,不多說了。我們來看一下輸出,會發現有很多不可思議的現象出現,因為每個人每次執行的結果都不一樣,所以這裡不貼結果了,不可思議的現象可能有://TestLayer.h class CTestLayer : public CCLayer { public: CTestLayer(void); ~CTestLayer(void); CREATE_FUNC(CTestLayer); virtual bool init(); pthread_t sellA_pid,sellB_pid;//執行緒id static int tickets;//票數 static void* threadA(void* p);//執行緒A回撥 static void* threadB(void* p);//執行緒B回撥 }; //TestLayer.cpp #include "TestLayer.h" int CTestLayer::tickets=100;//初始化票數100 CTestLayer::CTestLayer(void) { } CTestLayer::~CTestLayer(void) { } bool CTestLayer::init() { bool bRet=false; do { CC_BREAK_IF(!CCLayer::init()); pthread_create(&sellA_pid,NULL,threadA,0);//建立執行緒A pthread_create(&sellB_pid,NULL,threadB,0);//建立執行緒B bRet=true; } while (0); return bRet; } void* CTestLayer::threadA(void* p) { while(true) { if(tickets>0) { CCLog("A Sell %d",tickets--);//輸出售票,每次減1 } else { break; } } return NULL; } void* CTestLayer::threadB(void* p) { while(true) { if (tickets>0) { CCLog("B Sell %d",tickets--); } else { break; } } return NULL; }
(1)同一張票賣了2次。
(2)後面的票比前面的票先賣出去。
(3)第0張票竟然也可以賣。(這算站票麼。。。)
原因不多解釋了,時間片的問題,不明白的Google之。如果你覺得不會有這麼巧,那麼在列印結果前加上這麼一句:
Sleep(100);
人為干擾執行緒的執行,增大出錯機率。結果可能會是這樣:
A Sell 36 B Sell 36//賣2次了 A Sell 35 B Sell 34 A Sell 33 B Sell 32 A Sell 30//提早賣了 B Sell 31 B Sell 28 A Sell 29 A Sell 27 B Sell 26 A Sell 25 B Sell 24 A Sell 23 B Sell 22 A Sell 21 B Sell 20 A Sell 19 B Sell 18 A Sell 17 B Sell 16 A Sell 15 B Sell 14 A Sell 13 B Sell 12 A Sell 11 B Sell 10 A Sell 9 B Sell 8 A Sell 7 B Sell 6 A Sell 5 B Sell 4 A Sell 3 B Sell 2 A Sell 1 B Sell 0//站票。。。
3.利用互斥物件同步資料
這個問題主要是因為一個執行緒執行到一半的時候,時間片的切換導致另一個執行緒修改了同一個資料,當再次切換會原來執行緒並繼續往下執行的時候,資料由於被修改了導致結果出錯。所以我們要做的就是保證這個執行緒完全執行完,所以對執行緒加鎖是個不錯的注意,互斥物件mutex就是這個鎖。
3.1.初始化
在cpp外分配空間:
pthread_mutex_t CTestLayer::mutex;//mutex是靜態成員變數
在init中初始化,動態初始化:
pthread_mutex_init(&mutex,NULL);
3.2.加鎖和解鎖
以執行緒A為例:
void* CTestLayer::threadA(void* p) { while(true) { pthread_mutex_lock(&mutex);//加鎖 if(tickets>0) { Sleep(100); CCLog("A Sell %d",tickets--); pthread_mutex_unlock(&mutex);//解鎖 } else { pthread_mutex_unlock(&mutex);//解鎖 break; } } return NULL; }
3.3.釋放
在當前層的解構函式中:
pthread_mutex_destroy(&mutex);//前提要保證是解鎖狀態,否則會返回16的錯誤,釋放失敗
這個時候再看一下結果,Bingo!
B Sell 16
A Sell 15
B Sell 14
B Sell 13
B Sell 12
B Sell 11
B Sell 10
B Sell 9
B Sell 8
B Sell 7
B Sell 6
B Sell 5
B Sell 4
B Sell 3
B Sell 2
B Sell 1