从零学习开源项目系列(四)LogServer源码探究
从零学习开源项目系列(四)LogServer源码探究 这是从零学习开源项目的第四篇,上一篇是《从零学习开源项目系列(三) CSBattleMgr服务源码研究》,这篇文章我们一起来学习LogServer,中文意思可能是“日志服务器”。那么这个日志服务器到底做了哪些工作呢? 我们在Visual Studio中将LogServer设置为启动项,然后按F5将LogServer启动起来,启动成功后显示如下图: 从上图中,我们可以到大致做了三件事: 1. 创建一个侦听端口(端口号1234) 2. 连接mysql数据库 3. 初始化日志处理程序 我们来验证一下这三件事的细节。我们再Visual Studio中将程序中断(【调试】菜单-【全部中断】,快捷键Ctrl + Alt + Break)。然后在线程窗口查看这个程序所有的线程,如下图所示: 所有用红色旗帜标记的线程都是用户线程,我们可以查看这些线程的调用堆栈。我们从最上面的主线程开始: 切换到main函数,我们可以看出这里是一个循环: int main() { auto res = CLogHandler::GetInstance().Init(); if (res) { while(true) { INetSessionMgr::GetInstance()->Update(); Sleep(1); } } return 0; } 这里一个是初始化动作,一个循环中Update动作,它们具体做了些什么,我们先不管,我们先看其他线程做了什么,再回过头来看这里的代码。 我们接着看下一个线程的内容: 从调用堆栈来看,这是一个使用boost::thread启动的线程,这个线程函数代码如下: void Active::Run() { if (m_BeginInThreadCallback){ m_BeginInThreadCallback(); } while (true){ Consume(); } } 我们先看下这个线程函数做了什么,主要是m_BeginInThreadCallback和**Consume()函数,看下Consume()**函数: void Active::Consume(){ boost::mutex::scoped_lock lock(m_IOMutex); while(m_Queue.empty()){ m_ConditionVar.wait(lock); } m_SwapQueue.swap(m_Queue); lock.unlock(); while(!m_SwapQueue.empty()){ Buffer* pBuffer = m_SwapQueue.front(); m_SwapQueue.pop(); m_Callback(pBuffer); --m_PendingWorkNum; if (pBuffer){ m_pBufferPool.ReleaseObejct(pBuffer); } } } 这段代码很好理解,先使用条件变量挂起当前线程,条件变量触发后,如果消费者和生产者共有队列m_Queue中有数据,将公用的队列m_Queue临时倒换到本地的一个局部队列m_SwapQueue中,然后挨个处理队列m_SwapQueue中的数据。 这个线程在哪里创建的呢?通过搜索线程函数,我们找到如下代码: void Active::Start(){ bool ifHvTimer = !m_ThreadTimer.IsEmpty(); if (ifHvTimer){ m_Thread = boost::thread(&Active::RunWithUpdate, this); } else{ m_Thread = boost::thread(&Active::Run, this); } m_ThreadID = get_native_thread_id(m_Thread); char sThreadName[30]; sprintf(sThreadName, "%s-%d", "Actor-Run", GetActorID()); _SetThreadName(m_ThreadID, sThreadName); } 在上面这个函数中添加断点,重启下程序,很快会触发断点,我们看下断点触发时的调用堆栈:...