现在的位置: 首页 > 综合 > 正文

Chrome源代码分析之线程模型续1(十三)

2013年09月16日 ⁄ 综合 ⁄ 共 3755字 ⁄ 字号 评论关闭

MessagePumpForUI的代码:
void MessagePumpForUI::DoRunLoop() {
  // IF this was just a simple PeekMessage() loop (servicing all possible work
  // queues), then Windows would try to achieve the following order according
  // to MSDN documentation about PeekMessage with no filter):
  //    * Sent messages
  //    * Posted messages
  //    * Sent messages (again)
  //    * WM_PAINT messages
  //    * WM_TIMER messages
  //
  // Summary: none of the above classes is starved, and sent messages has twice
  // the chance of being processed (i.e., reduced service time).

  for (;;) {
    // If we do any work, we may create more messages etc., and more work may
    // possibly be waiting in another task group.  When we (for example)
    // ProcessNextWindowsMessage(), there is a good chance there are still more
    // messages waiting.  On the other hand, when any of these methods return
    // having done no work, then it is pretty unlikely that calling them again
    // quickly will find any work to do.  Finally, if they all say they had no
    // work, then it is a good time to consider sleeping (waiting) for more
    // work.

    bool more_work_is_plausible = ProcessNextWindowsMessage();
    if (state_->should_quit)
      break;

    more_work_is_plausible |= state_->delegate->DoWork();
    if (state_->should_quit)
      break;

    more_work_is_plausible |=
        state_->delegate->DoDelayedWork(&delayed_work_time_);
    // If we did not process any delayed work, then we can assume that our
    // existing WM_TIMER if any will fire when delayed work should run.  We
    // don't want to disturb that timer if it is already in flight.  However,
    // if we did do all remaining delayed work, then lets kill the WM_TIMER.
    if (more_work_is_plausible && delayed_work_time_.is_null())
      KillTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this));
    if (state_->should_quit)
      break;

    if (more_work_is_plausible)
      continue;

    more_work_is_plausible = state_->delegate->DoIdleWork();
    if (state_->should_quit)
      break;

    if (more_work_is_plausible)
      continue;

    WaitForWork();  // Wait (sleep) until we have work to do again.
  }

}

于I/O线程顺序不同,,UI线程首先执行windows系统消息,接着执行普通task,后面是延迟task,空闲task,最后调用WaitForWork()。

执行windows系统消息的是ProcessNextWindowsMessage函数,里面主要是一个典型的消息循环模型,首先调用PeekMessage取得消息,然后调用TranslateMessage和DispatchMessage把消息分发给正确的处理函数。UI线程本身创建的时候注册了一个默认处理函数WndProcThunk,它只处理kMsgHaveWork和WM_TIMER,其余的交给DefWindowProc。

与例如MFC的消息循环模型不同,MFC提取消息的API是GetMessage,这2者的主要区别是GetMessage会阻塞直到消息队列中出现了消息,PeekMessage则不会阻塞在这里,至于其他细节,可以查阅MSDN。为什么要使用PeekMessage,因为咱们的UI线程还有处理很多的task。

在看看UI线程的WaitForWork:

void MessagePumpForUI::WaitForWork() {
  int delay = GetCurrentDelay();
  if (delay < 0)  // Negative value means no timers waiting.
    delay = INFINITE;

  DWORD result;
  result = MsgWaitForMultipleObjectsEx(0, NULL, delay, QS_ALLINPUT,
                                       MWMO_INPUTAVAILABLE);
  if (WAIT_OBJECT_0 == result) {
    MSG msg = {0};
    DWORD queue_status = GetQueueStatus(QS_MOUSE);
    if (HIWORD(queue_status) & QS_MOUSE &&
       !PeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_NOREMOVE)) {
      WaitMessage();
    }
    return;
  }
  DCHECK_NE(WAIT_FAILED, result) << GetLastError();
}

MsgWaitForMultipleObjectsEx一直等待新的输入消息,直到超时。


而MessagePumpDefault的消息循环则是这样的:
void MessagePumpDefault::Run(Delegate* delegate) {
  DCHECK(keep_running_) << "Quit must have been called outside of Run!";

  for (;;) {
    mac::ScopedNSAutoreleasePool autorelease_pool;

    bool did_work = delegate->DoWork();
    if (!keep_running_)
      break;

    did_work |= delegate->DoDelayedWork(&delayed_work_time_);
    if (!keep_running_)
      break;

    if (did_work)
      continue;

    did_work = delegate->DoIdleWork();
    if (!keep_running_)
      break;

    if (did_work)
      continue;

    if (delayed_work_time_.is_null()) {
      event_.Wait();
    } else {
      TimeDelta delay = delayed_work_time_ - Time::Now();
      if (delay > TimeDelta()) {
        event_.TimedWait(delay);
      } else {
        // It looks like delayed_work_time_ indicates a time in the past, so we
        // need to call DoDelayedWork now.
        delayed_work_time_ = Time();
      }
    }
    // Since event_ is auto-reset, we don't need to do anything special here
    // other than service each delegate method.
  }

  keep_running_ = true;

}

而默认线程只处理各种task,一个循环结束,最后实际上是调用WaitForSingleObject阻塞到超时。

抱歉!评论已关闭.