Chromium多线程模型设计和视线分析_第1页
Chromium多线程模型设计和视线分析_第2页
Chromium多线程模型设计和视线分析_第3页
Chromium多线程模型设计和视线分析_第4页
Chromium多线程模型设计和视线分析_第5页
已阅读5页,还剩62页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、一个典型的异步通信过程如图1所示:图1  线程异步通信过程       Task-1被分解成三个子任务Task-1(1)、Task-1(2)和Task-1(3)。其中,Task-1(1)由Thread-1执行。Task-1(1)执行完成后,Thread-1通过我们在前面Chromium多线程通信的Closure机制分析一文分析的Closure请求Thread-2执行Task-1(2)。Task-1(2)执行完成后,Thread-2又通过一个Closure请求Thread-1执行Task-1(3)。至此,Task-1就执行完成。我们可以将第一个C

2、losure看作是一个Request操作,而第二个Closure是一个Reply操作。这是一个典型的异步通信过程。当然,如果不需要知道异步通信结果,那么第二个Closure和Task-1(3)就是不需要的。       假设Thread-1需要知道异步通信的结果,那么在图1中我们可以看到一个非常关键的点:Thread-1并不是什么也不干就只是等着Thread-2执行完成Task-1(2),它趁着这个等待的空隙,干了另外一件事情Task-2。如果我们将Thread-1看作是一个UI线程,那么就意味着这种异步通信模式是可以提高它的响应性的。  &#

3、160;    为了能够完成上述的异步通信过程,一个线程的生命周期如图2所示:图2 线程生命周期       线程经过短暂的启动之后(Start),就围绕着一个任务队列(TaskQueue)不断地进行循环,直到被通知停止为止(Stop)。在围绕任务队列循环期间,它会不断地检查任务队列是否为空。如果不为空,那么就会将里面的任务(Task)取出来,并且进行处理。这样,一个线程如果要请求另外一个线程执行某一个操作,那么只需要将该操作封装成一个任务,并且发送到目标线程的任务队列去即可。       为了

4、更好地理解这种基于任务队列的线程运行模式,我们脑补一下另外一种常用的基于锁的线程运行模式。一个线程要执行某一个操作的时候,就直接调用一个代表该操作的一个函数。如果该函数需要访问全局数据或者共享数据,那么就需要进行加锁,避免其它线程也正在访问这些全局数据或者共享数据。这样做的一个好处是我们只需要关心问题的建模,而不需要关心问题是由谁来执行的,只要保证逻辑正确并且数据完整即可。当然坏处也是显然的。首先是为了保持数据完整性,也就是避免访问数据时出现竞争条件,代码里面充斥着各种锁。其次,如果多个线程同时获取同一个锁,那么就会产生竞争。这种锁竞争会带来额外的开销,从而降低线程的响应性。  &#

5、160;    基于任务队列的线程运行模式,要求在对问题进行建模时,要提前知道谁是执行者。也就是说,在对问题进行建模时,需要指派好每一个子问题的执行者。这样我们为子问题设计数据结构时,就规定这些数据结构仅仅会被子问题的执行者访问。这样执行者在解决指派给它的问题时,就不需要进行加锁操作,因为在解决问题过程中需要访问的数据不会同时被其它执行者访问。这就是通过任务队列来实现异步通信的多线程模型的设计哲学。       当然,这并不是说,基于任务队列的线程运行模式可以完全避免使用锁,因为任务队列本身就是一个线程间的共享资源。想象一下,一个线程

6、要往里面添加任务,另一个线程要从里面将任务提取出来处理。因此,所有涉及到任务队列访问的地方都是需要加锁的。但是如果我们再仔细想想,那么就会发现,任务队列只是一个基础设施,它与具体的问题是无关的。因此,只要我们遵循上述设计哲学,就可以将代码里面需要加锁的地方仅限于访问任务队列的地方,从而就可以减少锁竞争带来的额外的开销。       这样说来,似乎基于任务队列的线程运行模式很好,但是实际上它对问题建模提出了更高的要求,也就是进行子问题划分时,要求划分出来的子问题是正交的,这样我们才有可能为这些子问题设计出不会同时被访问的数据结构。看到“正交”两个字,是不是

7、想起高数里面的向量空间的正交基了?或者傅里叶变换用到的一组三角函数了?其实道理就是一样一样的。       好了,说了这么多,我们就步入到正题,分析Chromium多线程模型的设计和实现,也就是基于任务队列的线程运行模式涉及到核心类图,如图3所示:图3 基于任务队列的线程运行模式核心类关系图       Thread是一个用来创建带消息循环的类。当我们创建一个Thread对象后,调用它的成员函数Start或者StartWithOptions就可以启动一个带消息循环的线程。其中,成员函数StartWithO

8、ptions可以指定线程创建参数。当我们不需要这个线程时,就可以调用之前创建的Thread对象的成员函数Stop。       Thread类继承了PlatformThread:Delegate类,并且重写了它的成员函数ThreadMain。我们知道,Chromium是跨平台的,这样各个平台创建线程使用的API有可能是不一样的。不过,我们可以通过PlatformThread:Delegate类为各个平台创建的线程提供一个入口点。这个入口点就是PlatformThread:Delegate类的成员函数ThreadMain。由于Thread类重写了父类Pla

9、tformThread:Delegate的成员函数ThreadMain,因此无论是哪一个平台,当它创建完成一个线程后,都会以Thread类的成员函数ThreadMain作为线程的入口点。       Thread类有一个重要的成员变量message_loop_,它指向的是一个MessageLoop对象。这个MessageLoop对象就是用来描述线程的消息循环的。MessageLoop类内部通过成员变量run_loop_指向的一个RunLoop对象和成员变量pump_指向的一个MessagePump对象来描述一个线程的消息循环。   

10、   一个线程在运行的过程中,可以有若干个消息循环,也就是一个消息循环可以运行在另外一个消息循环里面。除了最外层的消息循环,其余的消息的消息循环称为嵌套消息循环。我们为什么需要嵌套消息循环呢?这主要是跟模式对话框有关。       考虑一个情景,我们在一个窗口弹出一个文件选择对话框。窗口必须要等到用户在文件选择对话框选择了文件之后,才能去做其它事情。窗口是在消息循环过程中打开文件对话框的,它要等待用户在文件选择对话框中选择文件 ,就意味着消息循环被中止了。由于文件选择对话框也是通过消息循环来响应用户输入的,因此如果打开的它窗口中止了消

11、息循环,就会导致它无法响应用户输入。为了解决这个问题,就要求打开文件选择的窗口不能中止消息循环。方法就是该窗口创建一个子消息循环,该子消息循环负责处理文件选择对应框的输入事件,直到用户选择了一个文件为止。       MessageLoop类的成员变量run_loop_指向的一个RunLoop对象就是用来记录线程当使用的消息循环的。RunLoop类有三个重要的成员变量:       1. message_loop_,记录一个RunLoop对象关联的MessageLoop对象。    &

12、#160;  2. previous_loop_,记录前一个消息循环,当就是包含当前消息循环的消息循环。       3. run_depth_,记录消息循环的嵌套深度。       MessageLoop类的成员变量pump_指向的一个MessagePump对象是用来进行消息循环的,也就是说,Thread类描述的线程通过MessagePump类进入到消息循环中去。       Thread类将消息划分为三类,分别通过以下三个成员变量来描述:&#

13、160;      1. work_queue_,指向一个TaskQueue对象,用来保存那些需要马上处理的消息。       2. delayed_work_queue_,指向一个DelayedTaskQueue,用来保存那些需要延迟一段时间再处理的消息。       3. deferred_non_nestable_work_queue_,指向一个TaskQueue对象,用来保存那些不能够在嵌套消息循环中处理的消息。    

14、0;  一个MessagePump对象在进行消息循环时,如果发现消息队列中有消息,那么就需要通知关联的MessageLoop对象进行处理。通知使用的接口就通过MessagePump:Delegate类来描述。       MessagePump:Delegate类定义了四个成员函数,如下所示:       1. DoWork,用来通知MessageLoop类处理其成员变量work_queue_保存的消息。       2. DoDelayedWo

15、rk,用来通知MessageLoop类处理其成员变量delayed_work_queue_保存的消息。       3. DoIdleWork,用来通知MessageLoop类当前无消息需要处理,MessageLoop类可以利用该间隙做一些Idle Work。       4. GetQueueingInformation,用来获取MessageLoop类内部维护的消息队列的信息,例如消息队列的大小,以及下一个延迟消息的处理时间。       有了前面的基

16、础知识,接下来我们就可以大概描述Thread类描述的线程的执行过程。       首先是线程的启动过程:       1. 调用Thread类的成员函数Start或者StartWithOptions启动一个线程,并且以Thread类的成员函数ThreadMain作为入口点。       2. Thread类的成员函数ThreadMain负责创建消息循环,也就是通过MessageLoop类创建消息循环。       3.

17、0;MessageLoop类在创建消息循环的过程中,会通过成员函数Init创建用来一个用来消息循环的MessagePump对象。       4. 消息循环创建完成之后,调用MessageLoop类的成员函数Run进入消息循环。       5. MessageLoop类的成员函数Run创建一个RunLoop对象,并且调用它的成员函数Run进入消息循环。注意,该RunLoop对象在创建的过程,会关联上当前线程使用的消息循环,也就是创建它的MessageLoop对象。    &

18、#160;  6. RunLoop类的成员函数Run负责建立好消息循环的嵌套关系,也就是设置好它的成员变量previous_loop_和run_depth_等,然后就会调用其关联的MessageLoop对象的成员函数RunHandler进入消息循环。       7. MessageLoop类的成员函数RunHandler调用成员变量pump_描述的一个MessagePump对象的成员函数Run进入消息循环。       接下来是向线程的消息队列发送消息的过程。这是通过MessageL

19、oop类的以下四个成员函数向消息队列发送消息的:       1. PostTask,发送需要马上进行处理的并且可以在嵌套消息循环中处理的消息。       2. PostDelayedTask,发送需要延迟处理的并且可以在嵌套消息循环中处理的消息。       3. PostNonNestableTask,发送需要马上进行处理的并且不可以在嵌套消息循环中处理的消息。(已经移除了)       4.

20、0;PostNonNestableDelayedTask,发送需要延迟处理的并且不可以在嵌套消息循环中处理的消息。(已经移除了)       向线程的消息队列发送了新的消息之后,需要唤醒线程,这是通过调用MessagePump类的成员函数Schedule进行的。线程被唤醒之后 ,就会分别调用MessageLoop类重写父类MessagePump:Delegate的两个成员函数DoWork和DoDelayedWork对消息队列的消息进行处理。如果没有消息可以处理,就调用MessageLoop类重写父类MessagePump:Delegate的成员函数DoI

21、dleWork通知线程进入Idle状态,这时候线程就可以做一些Idle Work。       MessageLoop类的成员函数DoWork在处理消息的过程中,按照以下三个类别进行处理:       1. 对于可以马上处理的消息,即保存在成员变量work_queue_描述的消息队列的消息,执行它们的成员函数Run。       2. 对于需要延迟处理的消息,将它们保存在成员变量delayed_work_queue_描述的消息队列中,并且调用成员变量pump_指向的一个Mes

22、sagePump对象的成员函数ScheduleDelayedWork设置最早一个需要处理的延迟消息的处理时间,以便该MessagePump对象可以优化消息循环逻辑。       3. 对于可以马上处理但是不可以在嵌套消息循环中处理的消息,如果线程是处理嵌套消息循环中,那么将它们保存在成员变量deferred_non_nestable_work_queue_描述的消息队列中,这些消息将会在线程进入Idle状态时,并且是处理最外层消息循环时,得到处理。       以上就是Thread类描述的线程的大概执行过程,接下来

23、我们通过源码分析详细描述这些过程。 我们首先看线程的启动过程,即Thread类的成员函数Start的实现,如下所示: 1. bool Thread:Start()   2.   Options options;  3.   .  4.   return StartWithOptions(options);  5.          这个函数定义在文

24、件external/chromium_org/base/threading/thread.cc中。Thread类的成员函数Start调用另外一个成员函数StartWithOptions来启动一个线程,后者可以通过一个类型为Options的参数指定线程的启动参数,这里没有指定,意味着采用默认参数启动一个线程。       Thread类的成员函数StartWithOptions的实现如下所示: 1. bool Thread:StartWithOptions(const Options& options) &#

25、160; 2.   .  3. / Reset |id_| here to support restarting the thread.4. id_event_.Reset();5. id_ = kInvalidThreadId;6.7. SetThreadWasQuitProperly(false);8.9. MessageLoop:Type type = options.message_loop_type;10. if (!options.message_pump_factory.is_null()11. type = MessageLoo

26、p:TYPE_CUSTOM;12.13. message_loop_timer_slack_ = options.timer_slack;14. std:unique_ptr<MessageLoop> message_loop =15. MessageLoop:CreateUnbound(type, options.message_pump_factory);16. message_loop_ = message_loop.get();17. start_event_.Reset();18.19. / Hold the thread_lock_ while starting a n

27、ew thread, so that we can make sure20. / that thread_ is populated before the newly created thread accesses it.21. 22. AutoLock lock(thread_lock_);23. if (!PlatformThread:CreateWithPriority(options.stack_size, this, &thread_, options.priority) 24. DLOG(ERROR) << "failed to create thre

28、ad"25. message_loop_ = nullptr;26. return false;27. 28. 29.30. / The ownership of message_loop is managemed by the newly created thread31. / within the ThreadMain.32. ignore_result(message_loop.release();  33. .  34.   return true;  35.   &

29、#160;    这个函数定义在文件external/chromium_org/base/threading/thread.cc中。变量message_loop_type来创建指定Message Loop的类型 ,从而确定要创建的MessagePump。通过调用MessageLoop:CreateUnbound来生成一个MessageLoop。start_event_是创建的线程使用message_loop使用的信号。1. std:unique_ptr<MessageLoop> MessageLoop:CreateUnbound(2. Type type,3.

30、MessagePumpFactoryCallback pump_factory) 4. return WrapUnique(new MessageLoop(type, pump_factory);5.  1. template <typename T>2. std:unique_ptr<T> wrapUnique(T* ptr)3. 4. return std:unique_ptr<T>(ptr);5.  通过Messageloop的构造函数来生成。这个函数定义在文件external/chromium_org/base/message_l

31、oop/Message_loop.cc中。1. MessageLoop:MessageLoop(Type type, MessagePumpFactoryCallback pump_factory)2. : type_(type),3. .4. nestable_tasks_allowed_(true),5. pump_factory_(pump_factory),6. message_histogram_(NULL),7. run_loop_(NULL),8. incoming_task_queue_(new internal:IncomingTaskQueue(this),9. unbou

32、nd_task_runner_(10. new internal:MessageLoopTaskRunner(incoming_task_queue_),11. task_runner_(unbound_task_runner_),12. thread_id_(kInvalidThreadId) 13. / If type is TYPE_CUSTOM non-null pump_factory must be given.14. DCHECK(type_ != TYPE_CUSTOM | !pump_factory_.is_null(); 15.    

33、;MessageLoop类的成员变量type_描述的是消息循环的类型,nestable_tasks_allowed_描述当前是否允许处理嵌套消息,runn_loop_描述的是当前使用的消息循环。 同时创建了一个任务队列,并且保存在成员变量incoming_task_queue_中。这个任务队列通过IncomingQueue类来描述,它的定义如下所示:1. class BASE_EXPORT IncomingTaskQueue  2.     : public RefCountedThr

34、eadSafe<IncomingTaskQueue>   3.  public:  4.   .  5.   6.   bool AddToIncomingQueue(const tracked_objects:Location& from_here,  7.           

35、0;               const Closure& task,  8.                           Tim

36、eDelta delay,  9.                           bool nestable);  10.   11.   .  12.    13.  &#

37、160;void ReloadWorkQueue(TaskQueue* work_queue);  14.   15.   .  16.   17.   void WillDestroyCurrentMessageLoop();  18.    19.   .  20.   21.  private:  22

38、.   .  23.   24.   TaskQueue incoming_queue_;  25.   26.   .  27.   28.   MessageLoop* message_loop_;  29.   30.   .  31. ;      &

39、#160;  这个类定义在external/chromium_org/base/message_loop/incoming_task_queue.h中。 IncomingQueue类有两个重要的成员变量:       1. incoming_queue_,它描述的是一个TaskQueue,代表的是线程的消息队列,也就是所有发送给线程的消息都保存在这里。       2. message_loop_,它指向一个MessageLoop对象,描述的是线程的消息循环。  &

40、#160;    IncomingQueue类有三个重要的成员函数:       1. AddToIncomingQueue,用来向成员变量incoming_queue_描述的消息队列发送一个消息,并且唤醒线程进行处理。       2. ReloadWorkQueue,用来提取成员变量incoming_queue_描述的消息队列中的消息,并且保存在参数work_queue中。       3. WillDestroyCurr

41、entMessageLoop,当该函数被调用时,会将成员变量message_loop_的值设置为NULL,使得我们不能够再向线程发送消息,也就是请求线程执行某一个操作。task_runner_是SingleThreadTaskRunner类型的变量,作用包括有:向现有的线程的MessageLoop发布任务;创建他们自己的工作线程和 发送任务给的MessageLoop;将任务添加到一个 FIFO 和添加信号到非 MessageLoop 线程让他们来处理。unbound_task_runner_是SingleThreadTaskRunner类型的变量,通过MessageLoop创建和管理的Sing

42、leThreadTaskRunner的常用实现,只能作为MessageLoop的一部分。然后调用PlatformThread: CreateWithPriority方法。1. bool PlatformThread:CreateWithPriority(size_t stack_size, Delegate* delegate,2. PlatformThreadHandle* thread_handle,3. ThreadPriority priority) 4. return CreateThread(stack_size, true, / joinable thread5. delegat

43、e, thread_handle, priority);6.       这个函数定义在文件external/chromium_org/base/threading/PlatformThread.h中。具体的基于posix平台的实现在Platform_thread_posix.cc中,调用方法CreateThread来实现的。下面是CreateThread函数的主要代码。pthread_attr_init初始化一个线程对象的属性,需要用pthread_attr_destroy函数对其去除初始化。pthread_attr_setdetachstate设置线

44、程的分离状态。线程的分离状态决定一个线程以什么样的方式来终止自己。在默认情况下线程是非分离状态的,这种情况下,原有的线程等待创建的线程结束。只有当pthread_join()函数返回时,创建的线程才算终止,才能释放自己占用的系统资源。而分离线程不是这样子的,它没有被其他的线程所等待,自己运行结束了,线程也就终止了,马上释放系统资源。设置线程分离状态的函数为pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)。第二个参数可选为PTHREAD_CREATE_DETACHED(分离线程)和 PTHREAD _CREATE

45、_JOINABLE(非分离线程)。1. bool CreateThread( ) 2. DCHECK(thread_handle);3. base:InitThreading();4.   .  5. pthread_attr_init(&attributes);6.  .  7. if (!joinable)8. pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_DETACHED);9. . 10. int err = pthread_creat

46、e(&handle, &attributes, ThreadFunc, params.get();11. .  12. *thread_handle = PlatformThreadHandle(handle);13.14. pthread_attr_destroy(&attributes);15.   .  16.  这个函数定义在external/chromium_org/base/threading/ Platform_thread_posix.cc中,从这里就可以看到,调用POSIX线程库中的函数pth

47、read_create创建了一个线程,并且指定新创建的线程的入口点函数为ThreadFunc,同时传递给该入口点函数的参数为一个ThreadParams对象,该ThreadParams对象封装了线程启动过程中需要使用到的一系列参数。新创建线程的入口点函数ThreadFunc的实现如下所示:1. void* ThreadFunc(void* params)   2.   .  3.   ThreadParams* thread_params = static

48、_cast<ThreadParams*>(params);  4.   5.   PlatformThread:Delegate* delegate = thread_params->delegate;  6.   .  7.   8.   delegate->ThreadMain();  9.   10.   . 

49、; 11.   return NULL;  12.   这个函数定义在external/chromium_org/base/threading/platform_thread_posix.cc中。函数ThreadFunc首先将参数params转换为一个ThreadParams对象。有了这个ThreadParams对象之后,通过它的成员变量delegate获得一个PlatformThread:Delegate对象。从前面的调用过程可以知道, PlatformThread:Delegate对象实际是一个Thread对象

50、,用来描述新创建的线程。得到了用来描述新创建线程的Thread对象之后,就可以调用它的成员函数ThreadMain继续启动线程了。        Thread类的成员函数ThreadMain的实现如下所示:1. void Thread:ThreadMain()   2.     3.     .  4.     scoped_ptr<MessageLoop>

51、; message_loop;  5.     std:unique_ptr<MessageLoop> message_loop(message_loop_);6. message_loop_->BindToCurrentThread();7. message_loop_->SetTimerSlack(message_loop_timer_slack_); 8.     .  9.   10.  

52、60; / Let the thread do extra initialization.11. Init();12.13. 14. AutoLock lock(running_lock_);15. running_ = true;16. 17.18. start_event_.Signal();19.20. Run(message_loop_);21.22. 23. AutoLock lock(running_lock_);24. running_ = false;25. 26.27. / Let the thread do extra cleanup.28. CleanUp();

53、29.30. if (message_loop->type() != MessageLoop:TYPE_CUSTOM) 31. / Assert that MessageLoop:QuitWhenIdle was called by ThreadQuitHelper.32. / Don't check for custom message pumps, because their shutdown might not33. / allow this.34. DCHECK(GetThreadWasQuitProperly();35. 36.37. / We can't re

54、ceive messages anymore.38. / (The message loop is destructed at the end of this block)39. message_loop_ = nullptr; 40.     41.   这个函数定义在文件external/chromium_org/base/threading/thread.cc中。之前的MessageLoop已经通过其构造函数创建过。调用MessageLoop的BindToCurrentThread函数,函数定义如下:1. void M

55、essageLoop:BindToCurrentThread() 2. DCHECK(!pump_);3. if (!pump_factory_.is_null()4. pump_ = pump_factory_.Run();5. else6. pump_ = CreateMessagePumpForType(type_);7.8. DCHECK(!current() << "should only have one message loop per thread"9. lazy_tls_ptr.Pointer()->Set(this);10.11. in

56、coming_task_queue_->StartScheduling();12. unbound_task_runner_->BindToCurrentThread();13. unbound_task_runner_ = nullptr;14. SetThreadTaskRunnerHandle();15. 16. / Save the current thread's ID for potential use by other threads17. / later from GetThreadName().18. thread_id_ = PlatformThread

57、:CurrentId();19. subtle:MemoryBarrier();20. 21.  该函数调用另外一个成员函数CreateMessagePumpForType根据消息循环的类型创建一个消息泵(Message Pump),并且保存在成员变量pump_中。MessageLoop类的成员函数CreateMessagePumpForType的实现如下所示:1. #if defined(USE_GLIB) && !defined(OS_NACL)2. typedef MessagePumpGlib MessagePumpForUI;3. #elif defined

58、(OS_LINUX) && !defined(OS_NACL)4. typedef MessagePumpLibevent MessagePumpForUI;5. #endif6.7. #if defined(OS_IOS) | defined(OS_MACOSX)8. #define MESSAGE_PUMP_UI std:unique_ptr<MessagePump>(MessagePumpMac:Create()9. #elif defined(OS_NACL)10. / Currently NaCl doesn't have a UI Message

59、Loop.11. / TODO(abarth): Figure out if we need this.12. #define MESSAGE_PUMP_UI std:unique_ptr<MessagePump>()13. #else14. #define MESSAGE_PUMP_UI std:unique_ptr<MessagePump>(new MessagePumpForUI()15. #endif16.17. #if defined(OS_MACOSX)18. / Use an OS native runloop on Mac to support time

60、r coalescing.19. #define MESSAGE_PUMP_DEFAULT 20. std:unique_ptr<MessagePump>(new MessagePumpCFRunLoop()21. #else22. #define MESSAGE_PUMP_DEFAULT 23. std:unique_ptr<MessagePump>(new MessagePumpDefault()24. #endif25. .  26.   if (type = MessageLoop:TYPE_

61、UI)   27.     if (message_pump_for_ui_factory_)  28.       return message_pump_for_ui_factory_();  29.     return MESSAGE_PUMP_UI;  30.     31.  

62、 if (type = MessageLoop:TYPE_IO)  32.     return scoped_ptr<MessagePump>(new MessagePumpForIO();  33.34.   #if defined(OS_ANDROID)35. if (type = MessageLoop:TYPE_JAVA)36. return std:unique_ptr<MessagePump>(ne

63、w MessagePumpForUI();37. #endif38.   return scoped_ptr<MessagePump>(new MessagePumpDefault();  39.    这个函数定义在文件external/chromium_org/base/message_loop/message_loop.cc中。上面的代码通过一系列宏来适配不同的平台,这里我们只考虑Linux平台,这意味着MessagePumpForUI定义为MessagePumpLibevent,MES

64、SAGE_PUMP_UI定义为std:unique_ptr<MessagePump>(new MessagePumpForUI()。MESSAGE_PUMP_DEFAULT定义为std:unique_ptr<MessagePump>(new MessagePumpDefault()。       从MessageLoop类的成员函数CreateMessagePumpForType的实现可以知道:       1. 如果消息循环的类型为MessageLoop:TYPE_UI,那么对应的消息泵为

65、MessagePumpForUI,或者由函数指针message_pump_for_ui_factory_指向的函数创建。但是一般不设置函数指针message_pump_for_ui_factory_,因此,类型为MessageLoop:TYPE_UI的消息循环对应的消息泵为MessagePumpForUI。在Chromium中,消息循环类型为MessageLoop:TYPE_UI的线程称为UI线程,也就是应用程序的主线程。       2. 如果消息循环的类型为MessageLoop:TYPE_IO,那么对应的消息泵为MessagePumpFo

66、rIO,即MessagePumpLibevent。在Chromium中,消息循环类型为MessageLoop:TYPE_IO的线程称为IO线程,但是这里的IO不是读写文件的意思,而是执行IPC的意思。       3. 如果消息循环的类型为MessageLoop:TYPE_JAVA,那么对应的消息泵为MessagePumpForUI。在Chromium中,消息循环类型为MessageLoop:TYPE_JAVA的线程称为JAVA线程,它们与UI线程一样,在JAVA层具有自己的消息循环。       4. 其余类型的

67、消息循环,对应的消息泵为MessagePumpDefault。       总结来说,就是在Linux平台上,涉及到的消息泵有MessagePumpForUI、MessagePumpForIO和MessagePumpDefault三种,各自有不同的用途,其中MessagePumpForUI适用于具有自己的消息循环的UI线程,MessagePumpLibevent适用于用来负责执行IPC的IO线程,MessagePumpDefault适用于其它的一般线程。我们先从一般性出发,分析MessagePumpDefault的实现,后面再分析MessagePumpF

68、orUI和MessagePumpForIO的实现。       MessagePumpDefault类继承于MessagePump类,它的定义如下所示:1. class MessagePumpDefault : public MessagePump   2.  public:  3.   MessagePumpDefault();  4.   virtual MessagePumpDef

69、ault();  5.   6.   / MessagePump methods:  7.   virtual void Run(Delegate* delegate) OVERRIDE;  8.   virtual void Quit() OVERRIDE;  9.   virtual void ScheduleWork() OVERRIDE;  10.   virtual void ScheduleDelayedWork(cons

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论