1. 程式人生 > >Cocos2dx 3.0 過渡篇(二十七)C++11多線程std::thread的簡單使用(下)

Cocos2dx 3.0 過渡篇(二十七)C++11多線程std::thread的簡單使用(下)

fonts fun avi 2dx read 來源 cpp break 輸出

本篇接上篇繼續講:上篇傳送門:http://blog.csdn.net/star530/article/details/24186783

簡單的東西我都說的幾乎相同了,想挖點深的差點把自己給填進去。

以下實際演練一下。請同意我參考偶爾E往事的一篇線程的博客, 他用的是pThread。這裏我就用std::thread。


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;  
        }  
    }  
}

代碼非常easy。不多說了。我們來看一下輸出。會發現有非常多喜聞樂見的現象出現。由於每一個人每次執行的結果都不一樣。所以這裏不貼結果了,當中比較有意思的現象是同一張票賣了兩次?!
原因不多解釋了,時間片的問題,不明確的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沒有解鎖之前,其它使用這個相互排斥量加鎖的線程會一直處於等待狀態得不到執行

恩,就寫到這裏。

嘿嘿嘿嘿。

尊重原創,轉載請註明來源:http://blog.csdn.net/star530/article/details/24187103

Cocos2dx 3.0 過渡篇(二十七)C++11多線程std::thread的簡單使用(下)