Chromium多线程通信的Closure机制分析.docx
- 文档编号:5731828
- 上传时间:2022-12-31
- 格式:DOCX
- 页数:34
- 大小:85.39KB
Chromium多线程通信的Closure机制分析.docx
《Chromium多线程通信的Closure机制分析.docx》由会员分享,可在线阅读,更多相关《Chromium多线程通信的Closure机制分析.docx(34页珍藏版)》请在冰豆网上搜索。
Chromium多线程通信的Closure机制分析
Chromium多线程通信的Closure机制分析
为了充分利用CPU多核特性,Chromium在启动时会创建很多线程,来负责执行不同的操作。
这样就涉及到了多线程通信问题。
Chromium为每一个线程都创建了一个消息队列。
当一个线程需要另一个线程执行某一操作时,就向该线程的消息队列发送一个Closure。
这个Closure最终在目标线程中得到执行。
这种基于Closure的多线程通信方式在Chromium中使用得很普通,因此本文就对它的实现进行分析。
Closure从字面翻译就是闭包的意思,但是它与JavaScript或者C++11里面的闭包是不一样的,因为前者不像后者一样,会对作用域中的变量进行引用。
Chromium多线程通信用到的Closure实际上是一个特殊的Callback。
因此,本文实际要讲的是Chromium的Callback机制。
当我们理解了Chromium的Callback机制之后,就自然而然地理解Chromium多线程通信用到的Closure机制。
一个Callback从创建到调用的代码示例如下所示:
[cpp]viewplaincopy
voidMyFunc(inti,conststd:
:
string&str){}
base:
:
Callback : string&)>cb=base: : Bind(&MyFunc,23); cb.Run("helloworld"); 我们首先是调用函数base: : Bind创建了一个Callback对象。 这个Callback对象与函数MyFunc进行绑定,同时被绑定的还有函数MyFunc被调用时传递进去的第一个整型参数23。 我们接着调用了上述Callback对象的成员函数Run,并且给它传递了一个字符串参数“helloworld”。 这时候实际被调用的是函数MyFunc,并且传递给它的两个参数分别就为整数23和字符串“helloworld”。 如果我们把上面创建的Callback对象看作是一个Closure,那么它首先会被发送到目标线程的消息队列中,然后再在目标线程中调用它的成员函数Run,最后就会导致函数MyFunc在目标线程中被调用。 从上面的代码片段我们可以看到一个有趣的东西,那就是函数MyFunc被调用时传递进去的两个参数是分开指定的。 其中第一个参数在调用前指定的,而另一个参数是在调用时指定的。 实际上我们可以做到所有的参数均在调用前指定,以及所有的参数均在调用时指定。 当不是所有的参数均在调用时指定时,我们就可以简化一个函数的调用过程,即对一个函数实现了不同形式的调用,或者说可以使用不同的方式来调用一个函数。 此外,上面的代码片段创建的Callback对象是与一个全局函数绑定的。 实际上,一个Callback对象还可以与一个类的成员函数绑定,不过这时候在调用函数base: : Bind创建该Callback对象时,需要绑定一个对应的类对象,如下所示: [cpp]viewplaincopy classMyClass{ public: voidMyFunc(inti,conststd: : string&str){} }; MyClass*myclass=newMyClass; base: : Callback : Bind(&MyClass: : MyFunc,myclass,23,"helloworld"); 这里绑定的类对象就为myclass,并且是以为裸指针的形式指定的。 这时候我们就需要保证Callback对象cb的成员函数Run被调用时,对象myclass还没有被销毁。 为了更方便地管理被绑定对象的生命周期,函数base: : Bind允许通过我们在前面一文分析的scoped_refptr智能指针来绑定类对象,如下所示: [cpp]viewplaincopy scoped_refptr base: : Callback : Bind(&MyClass: : MyFunc,myclass,23,"helloworld"); Callback对象cb使用完成之后,对象myclass会自动释放,这样就可以保证Callback对象cb的成员函数Run被调用时,对象myclass是存在的。 我们甚至还可以通过我们在前面一文分析的WeakPtr弱智能指针来绑定类对象,如下所示: [cpp]viewplaincopy scoped_refptr base: : Callback : Bind(&MyClass: : MyFunc,GetWeakPtr(myclass),23,"helloworld"); 我们假设可以通过函数GetWeakPtr获得对象myclass的一个WeakPtr弱智能指针,这样当Callback对象cb的成员函数Run被调用时,如果对象myclass已经被销毁,那么就不会调用它的成员函数MyFunc。 最后,传递给最终被调用的函数的参数不仅可以是整型和字符串等基本类型,还可以是对象,如下所示: [cpp]viewplaincopy voidTakesOneRef(scoped_refptr scoped_refptr base: : Closurecb=base: : Bind(&TakesOneRef,f); 传递给被调用函数的对象可以通过裸指针传递,也可以通过在前面一文分析的scoped_ptr和scoped_refptr智能指针指定,这样就可以方便地管理被传递对象的生命周期。 接下来,我们就通过源代码来分析Chromium的Callback机制的实现,也就是Callback对象的创建和调用过程。 在分析Callback对象的创建和调用过程之前,我们首先看它的类关系图,如图1所示: 从图1可以看到,Callback类是从CallbackBase类继承下来的。 CallbackBase类有两个成员变量bind_state_和polymorphic_invoke_。 其中,成员变量bind_state_指向的是一个BindState对象,该BindState对象是保存了其宿主Callback对象创建时绑定的函数以及参数。 另外一个成员变量polymorphic_invoke_指向的是一个InvokeFuncStorage对象,该InvokeFuncStorage对象描述的是Invoker类的静态成员函数Run。 BindState类是从BindStateBase类继承下来的,BindStateBase类又是从RefCountedThreadSafe类继承下来的。 从前面一文可以知道,从RefCountedThreadSafe继承下来的类可以配合智能指针来使用,因此我们就可以看到CallbackBase类的成员变量bind_state_是一个引用了BindStateBase对象的scoped_refptr智能指针。 BindState类将宿主Callback对象创建时绑定的参数保存在成员变量p1_、p2_等中,绑定的函数则保存在成员变量runnable_指向的一个RunnableAdapter对象的成员变量function_中。 当CallbackBase类的成员函数Run被调用时,它们通过成员变量polymorphic_invoke_调用Invoker类的静态成员函数Run。 传递给Invoker类的静态成员函数Run的参数包括: 1.从父类BindStateBase继承下来的成员变量bind_state_指向的一个BindState对象; 2.传递给CallbackBase类的成员函数Run的参数。 Invoker类的静态成员函数Run从上述的BindState对象分别取出与它绑定的参数p1_、p2_等,以及RunnableAdapter对象,连同传递给CallbackBase类的成员函数Run的参数,一起再传递给InvokeHelper类的静态成员函数MakeItSo。 InvokeHelper类的静态成员函数MakeItSo接下来又会调用传递给它的RunnableAdapter对象的成员函数Run,后者又会调用保存在其成员变量function_的函数,这时候调用的实际上就是其关联的Callback对象绑定的函数。 大概理解了图1所示的Callback类关系图之后,接下来我们将以下面两个代码片段来分析Callback对象的创建和调用过程。 第一个代码片段如下所示: [cpp]viewplaincopy voidMyFunc(inti,conststd: : string&str){} base: : Callback : string&)>cb=base: : Bind(&MyFunc,23); cb.Run("helloworld"); 它调用的模板函数Bind的定义如下所示: [cpp]viewplaincopy template base: : Callback< typenameinternal: : BindState< typenameinternal: : FunctorTraits : RunnableType, typenameinternal: : FunctorTraits : RunType, void(typenameinternal: : CallbackParamTraits : StorageType)> : : UnboundRunType> Bind(Functorfunctor,constP1&p1){ //Typedefsforhowtostoreandrunthefunctor. typedeftypenameinternal: : FunctorTraits : RunnableTypeRunnableType; typedeftypenameinternal: : FunctorTraits : RunTypeRunType; ...... typedefinternal: : BindState void(typenameinternal: : CallbackParamTraits : StorageType)>BindState; returnCallback : UnboundRunType>( newBindState(internal: : MakeRunnable(functor),p1)); } 这个函数定义在文件chromium_org/base/bind.h中。 第二个代码片段如下所示: [cpp]viewplaincopy classMyClass{ public: voidMyFunc(inti,conststd: : string&str){} }; MyClass*myclass=newMyClass; base: : Callback : string&)>cb=base: : Bind(&MyClass: : MyFunc,myclass,23); cb.Run("helloworld"); 它调用的模板函数Bind的定义如下所示: [cpp]viewplaincopy template base: : Callback< typenameinternal: : BindState< typenameinternal: : FunctorTraits : RunnableType, typenameinternal: : FunctorTraits : RunType, void(typenameinternal: : CallbackParamTraits : StorageType, typenameinternal: : CallbackParamTraits : StorageType)> : : UnboundRunType> Bind(Functorfunctor,constP1&p1,constP2&p2){ //Typedefsforhowtostoreandrunthefunctor. typedeftypenameinternal: : FunctorTraits : RunnableTypeRunnableType; typedeftypenameinternal: : FunctorTraits : RunTypeRunType; ...... typedefinternal: : BindState void(typenameinternal: : CallbackParamTraits : StorageType, typenameinternal: : CallbackParamTraits : StorageType)>BindState; returnCallback : UnboundRunType>( newBindState(internal: : MakeRunnable(functor),p1,p2)); } 这个函数定义在文件chromium_org/base/bind.h中。 上述两个模板函数Bind做了三件事情: 1.调用模板函数MakeRunnable创建了一个RunnableAdapter对象; 2.使用上述对应的RunnableAdapter对象和参数p1创建了一个BindState对象; 3.使用上述BindState对象创建了一个Callback对象。 接下来我们就要继续分析上述三对象的创建过程,不过在分析之前,我们需要理解这里涉及到的两个模板类FunctorTraits和CallbackParamTraits的定义和作用。 模板类FunctorTraits的定义如下所示: [cpp]viewplaincopy template structFunctorTraits{ typedefRunnableAdapter typedeftypenameRunnableType: : RunTypeRunType; }; 这个类定义在文件chromium_org/base/bind_internal.h中。 这里的模板参数T描述的是一个函数,例如,对于上述的第一个代码片段,T就为void(*)(int,conststd: : string&),而对于第二个代码片段,T就为void(MyClass: : *)(int,conststd: : string&),这个模板参数T又作为参数用来定义RunnableAdapter。 当模板参数T等于void(*)(int,conststd: : string&)时,RunnableAdapter : RunnableType的定义,如下所示: [cpp]viewplaincopy template classRunnableAdapter public: typedefR(RunType)(A1,A2); explicitRunnableAdapter(R(*function)(A1,A2)) : function_(function){ } RRun(typenameCallbackParamTraits : ForwardTypea1, typenameCallbackParamTraits : ForwardTypea2){ returnfunction_(CallbackForward(a1),CallbackForward(a2)); } private: R(*function_)(A1,A2); }; 这个类定义在文件external/chromium_org/base/bind_internal.h中。 这时候FunctorTraits : RunType就正好描述的是上述的FunctorTraits模板参数T,即void(*)(int,conststd: : string&)。 当模板参数T等于为void(MyClass: : *)(int,conststd: : string&)时,RunnableAdapter : RunnableType的定义,如下所示: [cpp]viewplaincopy template classRunnableAdapter : *)(A1,A2)>{ public: typedefR(RunType)(T*,A1,A2); typedeftrue_typeIsMethod; explicitRunnableAdapter(R(T: : *method)(A1,A2)) : method_(method){ } RRun(T*object,typenameCallbackParamTraits : ForwardTypea1, typenameCallbackParamTraits : ForwardTypea2){ return(object->*method_)(CallbackForward(a1),CallbackForward(a2)); } private: R(T: : *method_)(A1,A2); }; 这个类定义在文件external/chromium_org/base/bind_internal.h中。 这时候FunctorTraits : RunType就正好描述的是上述的FunctorTraits模板参数T,即void(MyClass: : *)(int,conststd: : string&)。 从上面的分析就可以看出,模板类FunctorTraits实际上是用来描述一个函数的签名的。 我们再来看模板类CallbackParamTraits的定义,如下所示: [cpp]viewplaincopy template : value> structCallbackParamTraits{ typedefconstT&ForwardType; typedefTStorageType; }; 这个类定义在文件chromium_org/base/callback_internal.h中。 模板类CallbackParamTraits不单止在前面的函数Bind用到,在前面列出的两个模板类RunnableAdapter中也有用到,它是用来描述一个函数参数的签名的。 例如,对于上述两个代码片段,模板参数T描述的就是一个类型为conststd: : string的参数。 从模板类CallbackParamTraits的定义还可以看到,CallbackParamTraits: : ForwardType描述的是参数的引用类型,而CallbackParamTraits: : StorageType描述的是参数的值类型。 例如,对于上述第一个代码片段,CallbackParamTraits : ForwardType的是一个类型为int&的参数,而CallbackParamTraits : StorageType描述的是一个类型为int的参数。 模板类CallbackParamTraits还有一个模板参数is_move_only,它的默认值等于IsMoveOnlyType IsMoveOnlyType [cpp]viewplaincopy template template staticYesTypeTest(consttypenameU: : MoveOnlyTypeForCPP03*); template staticNoTypeTest(...); staticconstboolvalue=sizeof(Test ! is_const : value; }; 这个类定义在文件external/chromium_org/base/callback_internal.h中。 模板类IsMoveOnlyType 关于类型的move语意,我们在前面一文中有提交到,它所表达的意思就是当我们用一个右值引用作为参数构造一个相同类型的对象时,新构造的对象将直接使用右值引用所描述的临时对象,而不是通过拷贝右值引用描述的临时对象来构造新的对象。 因此,我们就可以看出,当调用模板类IsMoveOnlyType 从前面一文可以知道,当一个类的定义嵌套了宏MOVE_ONLY_TYPE_FOR_CPP_03时,该类就是有具有move语意的,例如
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Chromium 多线程 通信 Closure 机制 分析