第二人生里使用線程循環來處理消息,這樣的結構就比較清晰。比如有一個寫文件的請求,就可以把這個請求放到線程隊列里,然后喚醒線程,讓線程處理這個請求。那么在第二人生里是怎么樣構造消息循環呢?又是怎么樣執行其它線程發過來的請求呢?帶著這兩個問題來分析下面這幾段代碼。
#001?void LLQueuedThread::run()
#002?{
?
下面實現消息循環。
#003?
???? while (1)
#004?
???? {
#005?
??????????? // this will block on the condition until runCondition() returns true, the thread is unpaused, or the thread leaves the RUNNING state.
?
下面檢查是否暫停線程執行。
#006?
??????????? checkPause();
#007?
???????????
?
檢查線程是否要結束循環。
#008?
??????????? if(isQuitting())
#009?
?????????????????? break;
#010?
#011?
??????????? //llinfos << "QUEUED THREAD RUNNING, queue size = " << mRequestQueue.size() << llendl;
#012?
?
標志線程已經非空閑狀態。
#013?
??????????? mIdleThread = FALSE;
#014?
???????????
?
調用processNextRequest函數來處理本線程消息隊列里的消息。
#015?
??????????? int res = processNextRequest();
#016?
??????????? if (res == 0)
#017?
??????????? {
#018?
?????????????????? mIdleThread = TRUE;
#019?
??????????? }
#020?
???????????
?
處理線程消息出錯,退出線程循環。
#021?
??????????? if (res < 0) // finished working and want to exit
#022?
??????????? {
#023?
?????????????????? break;
#024?
??????????? }
#025?
#026?
??????????? //LLThread::yield(); // thread should yield after each request??????????
#027?
???? }
#028?
#029?
???? llinfos << "QUEUED THREAD " << mName << " EXITING." << llendl;
#030?}
?
由線程接口類LLThread就知道,線程里主要處理函數是run(),而在LLThread繼承類LLQueuedThread里也就是實現了這個函數的功能,主要就是調用函數processNextRequest來處理消息隊列里的消息。下面就來分析函數processNextRequest的代碼,如下:
?
#001?
#002?S32 LLQueuedThread::processNextRequest()
#003?{
#004?
???? QueuedRequest *req;
#005?
???? // Get next request from pool
?
鎖住線程消息隊列。
#006?
???? lockData();
?
循環地找到可用的消息。
#007?
???? while(1)
#008?
???? {
#009?
??????????? req = NULL;
?
線程消息隊列為空,退出處理消息。
#010?
??????????? if (mRequestQueue.empty())
#011?
??????????? {
#012?
?????????????????? break;
#013?
??????????? }
?
獲取第一個消息請求。
#014?
??????????? req = *mRequestQueue.begin();
?
刪除第一個消息請求。
#015?
??????????? mRequestQueue.erase(mRequestQueue.begin());
?
判斷是否丟掉這個消息請求。
#016?
??????????? if ((req->getFlags() & FLAG_ABORT) || (mStatus == QUITTING))
#017?
??????????? {
#018?
?????????????????? req->setStatus(STATUS_ABORTED);
#019?
?????????????????? req->finishRequest(false);
#020?
?????????????????? if (req->getFlags() & FLAG_AUTO_COMPLETE)
#021?
?????????????????? {
#022?
????????????????????????? mRequestHash.erase(req);
#023?
????????????????????????? req->deleteRequest();
#024?//
????????????????????? check();
#025?
?????????????????? }
#026?
?????????????????? continue;
#027?
??????????? }
#028?
??????????? llassert_always(req->getStatus() == STATUS_QUEUED);
#029?
??????????? break;
#030?
???? }
?
設置這個消息正在處理過程中。
#031?
???? if (req)
#032?
???? {
#033?
??????????? req->setStatus(STATUS_INPROGRESS);
#034?
???? }
?
解鎖消息隊列。
#035?
???? unlockData();
#036?
#037?
???? // This is the only place we will call req->setStatus() after
#038?
???? // it has initially been seet to STATUS_QUEUED, so it is
#039?
???? // safe to access req.
?
下面開始處理獲取到的消息。
#040?
???? if (req)
#041?
???? {
?
開始調用這個消息的特別處理函數。
#042?
??????????? // process request
#043?
??????????? bool complete = req->processRequest();
#044?
?
判斷這個請求是否完成。
#045?
??????????? if (complete)
#046?
??????????? {
#047?
?????????????????? lockData();
#048?
?????????????????? req->setStatus(STATUS_COMPLETE);
#049?
?????????????????? req->finishRequest(true);
#050?
?????????????????? if (req->getFlags() & FLAG_AUTO_COMPLETE)
#051?
?????????????????? {
#052?
????????????????????????? mRequestHash.erase(req);
#053?
????????????????????????? req->deleteRequest();
#054?//
????????????????????? check();
#055?
?????????????????? }
#056?
?????????????????? unlockData();
#057?
??????????? }
#058?
??????????? else
#059?
??????????? {
#060?
?????????????????? lockData();
#061?
?????????????????? req->setStatus(STATUS_QUEUED);
#062?
?????????????????? mRequestQueue.insert(req);
#063?
?????????????????? U32 priority = req->getPriority();
#064?
?????????????????? unlockData();
#065?
?????????????????? if (priority < PRIORITY_NORMAL)
#066?
?????????????????? {
#067?
????????????????????????? ms_sleep(1); // sleep the thread a little
#068?
?????????????????? }
#069?
??????????? }
#070?
???? }
#071?
?
查看是否需要退出線程。
#072?
???? S32 res;
#073?
???? S32 pending = getPending();
#074?
???? if (pending == 0)
#075?
???? {
#076?
??????????? if (isQuitting())
#077?
??????????? {
#078?
?????????????????? res = -1; // exit thread
#079?
??????????? }
#080?
??????????? else
#081?
??????????? {
#082?
?????????????????? res = 0;
#083?
??????????? }
#084?
???? }
#085?
???? else
#086?
???? {
#087?
??????????? res = pending;
#088?
???? }
#089?
???? return res;
#090?}
#091?
?
通過在processNextRequest里調用更加具體的消息處理函數processRequest來實現各個消息處理,由于processRequest也是純虛函數,因此通過實現這個函數不同的形式,就可以實現不同的內容處理,這就是C++的多態特性。不過,要注意的是這個函數可能由多線程訪問,需要進行同步的操作。
?
?
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
