zoukankan      html  css  js  c++  java
  • Chormium线程模型及应用指南

    核心概念

    设计上遵循以下原则:

    1 不要在UI线程做不论什么堵塞式的I/O操作,以及其他耗时的操作,通过消息传递把各种操作传给相应用途的线程去做。

    2 不鼓舞线程加锁机制和线程安全对象。

    对象仅仅存在一个线程。通过消息来实现线程之间的通信,线程之间不互相堵塞。通过callback对象实现跨线程请求。

    普通情况下,我们应该利用一个现有的线程,尽量不要创建新的线程。

    UI线程实际上会被设置为不同意I/O操作。而且不同意等待。 


    线程列表

    核心线程列表

    所属进程线程名称类型职责实现
     BrowserUI / BrowserThreadJavaBrowser的主线程content::BrowserThreadImpl
     Browser Chrome_DBThreadNative负责数据库(SQLite)相关的操作,非常多功能的实现会用到该线程。

    content::BrowserThreadImpl
     Browser Chrome_FileThreadNative文件的创建、删除、读写等。content::BrowserThreadImpl
     Browser Chrome_FileUserBlockingThreadNative用于读取与用户交互有关的数据,须要高速的响应。看到net log模块和appcache实用。

    content::BrowserThreadImpl
     Browser Chrome_ProcessLauncherThreadNative用于启动和终止子进程。content::BrowserThreadImpl
     Browser Chrome_CacheThreadNative  
        content::BrowserThreadImpl
     Browser IndexedDBNativeIndexDB存储线程。

    base::Thread
    GPU Chrome_InProcGpuThreadNativeGPU的单进程版本号实现。content::InProcessGpuThread
    Child ProcessesChrome_ChildIOThreadNative子进程的IO线程实现。

    base::Thread
    RendererChrome_InProcRendererThreadNativeRenderer进程的单进程版本号实现。

    content::InProcessRendererThread

     

    其他线程

    线程名称Module实现说明
    CookieMonsterClientCAWbase::Thread 
    CookieMonsterBackendCAWbase::Thread 
    CookieSyncManagerWebViewRunnable 
    Chrome_libJingle_WorkerThreadBrowserbase::Thread 
    Blink Heap Marker Thread (*)Blinkbase::Thread 
    Blink GC Sweeper (*)Blinkbase::Thread 
    HTMLParserThreadBlinkbase::Thread 
    AsyncTransferThreadgpugpu::TransferThread 
    BrowserBlocking WorkerBrowserbase::SequencedWorkerPool详见:Chromium中应用C/C++并发技术要点
    SimpleCache Workernetbase::SequencedWorkerPool 
    Network File Threadnetbase::Thread 

      

    线程结构

    (以单进程模型说明)

    Android下线程的消息结构


    Chromium的线程结构


    各个类的职责说明:

    职责说明
    RunLoop

    一个辅助类,主要封装消息循环 MessageLoop 类,其本
    身没有特别的功能,主要提供一组公共接口被调用,其实质是调用 MessageLoop 类的接口和实现

    MessageLoop

    主消息循环,原理上讲,它应该能够处理三种类型的消息,包括支持不同平台的消息。

    其实,假设让它处理全部这些消息,这会让其代码结构复杂不清难以理解。

    消息循环仅仅须要三种类型:

    • 一种仅能处理自己定义任务
    • 一种能处理自己定义任务和 IO 操作
    • 一种是能处理自己定义任务和 UI 消息。


    非常自然地,Chromium 定义一个基类 MessageLoop 用于处理自己定义任务,两个子类相应于第二和第三种类型。

    对于第二和第三种 MessageLoop 类型,它们除了要处理任务外,还要处理平台相关的消息,为了结构清晰,
    chromium 定义一个新的基类及其子类来负责处理它们,这就是 MessagePump。MessagePump 的每一个子类针对不同平台
    和不同的消息类型。

    MessagePump

    一个抽象出来的基类,能够用来处理上面所列的第二和第三种消息类型。对于每一个平台,它们有不同的
    MessagePump 的子类来相应,这些子类被包括在 MessageLoopForUI 和 MessageLoopForIO 类中。

    摘自:<<理解WebKit和Chromium>> 


    Browser端线程结构



    Browser端抛转线程消息,主要是基于BrowserThread提供的方法来完毕的,例如以下:

    // 检測所在的线程
    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     
    // 抛转任务到UI线程运行
    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
            base::Bind(&AwLoginDelegate::HandleHttpAuthRequestOnUIThread,
                       this, (count->auth_attempts_ == 0)));
     
    // 抛转任务到IO线程
    BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
          base::Bind(&AwLoginDelegate::ProceedOnIOThread,
                     this, user, password));

     

     

    Render端的线程结构 



    Renderer端抛转消息,主要是基于MessageLoopProxy来完毕。例如以下:

    base::Closure closure =
            base::Bind(&CompositorOutputSurface::ShortcutSwapAck,
                       weak_ptrs_.GetWeakPtr(),
                       output_surface_id_,
                       base::Passed(&frame->gl_frame_data),
                       base::Passed(&frame->software_frame_data));
    base::MessageLoopProxy::current()->PostTask(FROM_HERE, closure);
     
    // input_event_filter.cc中的演示样例
    io_loop_->PostTask(FROM_HERE,
                         base::Bind(&InputEventFilter::SendMessageOnIOThread,
                                    this,
                                    base::Passed(&message)));
     
    // Blink platform implemetation
    base::MessageLoopProxy::current()->PostTask(
          FROM_HERE,
          base::Bind(&PlatformEventObserverBase::SendFakeDataForTesting,
                     base::Unretained(observer), data));

     

    gpu与Browser/Renderer的交互




    线程安全

    对于Java及Android的线程安全不再展开。能够參考附件的资料:<<Efficient Android Threading Asynchronous Processing Techniques for Android Applications>>

    关于Java则推荐《Java并发实战》。

    最经常使用的形式,将使用的对象定义为base::RefCountedThreadSafe。保证引用的对象不会被提前析构。

    对于一些非线程安全的类能够使用NonThreadSafe提供Debug模式下线程安全确认。也能够应用ThreadCollisionWarner/ThreadChecker 确保运行线程与设计一致。

    详见:Chromium中应用C/C++并发技术要点

    參考: 怎样安全的使用PostTask


    任务的取消

    除了任务按须要取消外,假设在宿主类析构后运行就可能导致崩溃。

    眼下使用两种方式保证任务的取消:

        WeakPtrFactory (WeakPtr)和CancelableTaskTracker, 它们析构时也会自己主动将任务取消。

    CancelableTaskTracker能够參考Chromium官网的说明或是在FaviconCache中的应用。

    class UserInputHandler : public base::RefCountedThreadSafe<UserInputHandler> {
      // Runs on UI thread.
      void OnUserInput(Input input) {
        CancelPreviousTask();
        DBResult* result = new DBResult();
        task_id_ = tracker_->PostTaskAndReply(
            BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB).get(),
            FROM_HERE,
            base::Bind(&LookupHistoryOnDBThread, this, input, result),
            base::Bind(&ShowHistoryOnUIThread, this, base::Owned(result)));
      }
     
      void CancelPreviousTask() {
        tracker_->TryCancel(task_id_);
      }
     
      ...
     
     private:
      CancelableTaskTracker tracker_;  // Cancels all pending tasks while destruction.
      CancelableTaskTracker::TaskId task_id_;
      ...
    };

     

    对于WeakPtr。Chromium已经封装了一个WeakptrFactory供使用。能够參考GpuBrowserCompositorOutputSurface中的使用。

    使用方式比較简单。但没有CancelableTaskTracker通用。

    以下是一个简单的演示样例(使用WeakPtrFactory<>最大的优点是不用改动类的定义.)

    class MyObject {
     public:
      MyObject() : weak_factory_(this) {}
     
      void DoSomething() {
        const int kDelayMS = 100;
        MessageLoop::current()->PostDelayedTask(FROM_HERE,
            base::Bind(&MyObject::DoSomethingLater, weak_factory_.GetWeakPtr()),
            kDelayMS);
      }
     
      void DoSomethingLater() {
        ...
      }
     
     private:
      base::WeakPtrFactory<MyObject> weak_factory_;
    };
    *非线程安全,能够跨线程传递,但必须在一个线程上使用这个WeakPtr,即仅仅能在运行在同样线程的任务上使用这个机制。

    *类中WeakPtrFactory<Foo> weak_factory_的成员须要放在全部其他成员的后面,确保其他成员的析构函数运行的时候WeakPtrs还是无效的。
    

      

    关于WeakPtr的进一步解释能够參考: Chromium中的weak_ptr,以及 关于SupportWeakPtr与WeakPtrFactory的选择


  • 相关阅读:
    ANDROID笔记:通过ContentProvider得到SD卡的图片
    android:ViewPager显示Fragment(碎片)
    ANDROID笔记:使用动画替代viewpager的header
    ANDROID笔记:ListPopupWindow的使用
    ANDROID笔记:Activity的显式和隐式调用
    ANDROID笔记:Activity之间的传值
    go语言下载页面html代码(d3.js代码)
    如何使用sas proc过程步产生的结果
    福昕PDF阅读器的图章妙用
    测试成功的d3.js代码
  • 原文地址:https://www.cnblogs.com/gavanwanggw/p/6970967.html
Copyright © 2011-2022 走看看