第二人生的源码分析(四十二)实现消息处理的线程类

第二人生里使用线程循环来处理消息,这样的结构就比较清晰。比如有一个写文件的请求,就可以把这个请求放到线程队列里,然后唤醒线程,让线程处理这个请求。那么在第二人生里是怎么样构造消息循环呢?又是怎么样执行其它线程发过来的请求呢?带着这两个问题来分析下面这几段代码。
#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++的多态特性。不过,要注意的是这个函数可能由多线程访问,需要进行同步的操作。
 
 
posted @ 2008-04-21 21:43  ajuanabc  阅读(120)  评论(0编辑  收藏  举报