chromium多线程间通信机制分析
2018-01-16 21:28
239 查看
chromium中会创建多个线程,分别执行不同的操作,它会为每个线程创建一个消息队列,当一个线程需另外一个线程执行某个任务时,会向该线程发送一个closure,使得该closure在目标线程执行。从而达到多线程通信的目的。其中closure的本质为一个特殊的callback函数。
chromium中callback的创建调用过程如下代码所示:
上述代码中base::Bind创建了一个callback对象,该对象绑定了一个函数及其的一个参数,该对象可以看做时一个closure对象,chromium需要进行线程间通信时,即将它发送到目标线程中,目标线程调用Run方法,可以使得函数MyFunc在目标线程被调用。
同时从上述代码可以看出,函数MyFunc的参数可以在绑定时指定,也可以在目标线程中调用时候指定,而函数MyFunc可以是定义的全局函数,也可以时类的成员函数,但是在调用base::bind创建该callback对象时,需要绑定一个对应的类对象。实例代码如下所示
这里绑定的对象即为myclass,这样的调用方式存在一定的风险,在目标线程调用该对象时无法确保该对象还存在。因此可以使用chromium中的智能指针来绑定相关对象。
Callback对象cb使用完成之后,对象myclass会自动释放,这样就可以保证Callback对象cb的成员函数Run被调用时,对象myclass是存在的。 我们甚至还可以通过WeakPtr弱智能指针来绑定类对象。
接下来分析chromium中callback对象的创建和调用过程。首先Callback与其他类的类图如下所示
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对象绑定的函数。
下面从几个代码片段来分析Callback的创建和调用过程,Bind函数的其中一个定义如下所示
可以看出来主要做了三件事情:
1.调用internal::MakeRunnable创建了一个RunnableAdapter对象。
2.调用BindState的构造函数,传入两个参数分别为RunnableAdapter对象,p1。
3.由BindState对象构造一个Callback对象。
其中MakeRunnable实现如下代码所示:
从中我们就可以知道,Chromium里面的Callback机制实际上就是预先通过一系列预定义的C++模板类和C++模板函数来实现的,使得我们可以将一些预先指定的参数和函数绑定在一个BindState对象和一个RunnableAdapter对象中,并且封装在一个Callback对象中,最后以Callback类的成员函数Run作为统一的调用接口来间接地调用预先绑定的函数,并且将预先指定的参数以及调用Callback类的成员函数Run指定的参数传递给它。
这种Callback机制适合用作线程间异步通信。假设有两个线程A和B,其中线程A希望在线程B中执行一个任务。这时候线程A就可以将该任务封装成一个Callback对象,并且将该Callback对象发送到线程B的任务队列去。于是线程B调度该Callback对象时,不需要知道它描述的是一个什么样的任务,只需要统一地调用它的成员函数Run,就可以让它执行一个具体的任务。
Chromium将这种用于线程间异步通信的Callback对象称为Closure对象,如下所示:
这意味着一个Closure对象是这样的一个Callback对象:
1.被调用的函数,以及调用该函数时使用的所有参数,都必须预先指定,也就是不能在调用时指定。
2. 被调用的函数的返回值为void。
满足上述条件的Callback对象就称为Closure对象,也就是Chromium多线程通信的Closure机制
chromium中callback的创建调用过程如下代码所示:
void MyFunc(int i, const std::string& str) {} base::Callback<void(const std::string&)> cb = base::Bind(&MyFunc, 23); cb.Run("hello world");
上述代码中base::Bind创建了一个callback对象,该对象绑定了一个函数及其的一个参数,该对象可以看做时一个closure对象,chromium需要进行线程间通信时,即将它发送到目标线程中,目标线程调用Run方法,可以使得函数MyFunc在目标线程被调用。
同时从上述代码可以看出,函数MyFunc的参数可以在绑定时指定,也可以在目标线程中调用时候指定,而函数MyFunc可以是定义的全局函数,也可以时类的成员函数,但是在调用base::bind创建该callback对象时,需要绑定一个对应的类对象。实例代码如下所示
class MyClass { public: void MyFunc(int i, const std::string& str) }; MyClass myclass = new Myclass; base::Callback<void(void)> cb = base::bind(&MyClass::MyFunc, myclass, 23, "helloworld"); cb.Run();
这里绑定的对象即为myclass,这样的调用方式存在一定的风险,在目标线程调用该对象时无法确保该对象还存在。因此可以使用chromium中的智能指针来绑定相关对象。
class MyClass { public: void MyFunc(int i, const std::string& str) }; scoped_refptr<MyClass> myclass(new MyClass); base::Callback<void(void)> cb = base::Bind(&MyClass::MyFunc, myclass, 23, "hello world"); cb.Run();
Callback对象cb使用完成之后,对象myclass会自动释放,这样就可以保证Callback对象cb的成员函数Run被调用时,对象myclass是存在的。 我们甚至还可以通过WeakPtr弱智能指针来绑定类对象。
class MyClass { public: void MyFunc(int i, const std::string& str) }; scoped_refptr<MyClass> myclass(new MyClass); base::Callback<void(void)> cb = base::Bind(&MyClass::MyFunc, GetWeakPtr(myclass), 23, "hello world"); cb.Run();
接下来分析chromium中callback对象的创建和调用过程。首先Callback与其他类的类图如下所示
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对象绑定的函数。
下面从几个代码片段来分析Callback的创建和调用过程,Bind函数的其中一个定义如下所示
template <typename Functor, typename P1> base::Callback< typename internal::BindState< typename internal::FunctorTraits<Functor>::RunnableType, typename internal::FunctorTraits<Functor>::RunType, void(typename internal::CallbackParamTraits<P1>::StorageType)> ::UnboundRunType> Bind(Functor functor, const P1& p1) { // Typedefs for how to store and run the functor. typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType; typedef typename internal::FunctorTraits<Functor>::RunType RunType; // Use RunnableType::RunType instead of RunType above because our // checks should below for bound references need to know what the actual // functor is going to interpret the argument as. typedef internal::FunctionTraits<typename RunnableType::RunType> BoundFunctorTraits; // Do not allow binding a non-const reference parameter. Non-const reference // parameters are disallowed by the Google style guide. Also, binding a // non-const reference parameter can make for subtle bugs because the // invoked function will receive a reference to the stored copy of the // argument and not the original. COMPILE_ASSERT( !(is_non_const_reference<typename BoundFunctorTraits::A1Type>::value ), do_not_bind_functions_with_nonconst_ref); // For methods, we need to be careful for parameter 1. We do not require // a scoped_refptr because BindState<> itself takes care of AddRef() for // methods. We also disallow binding of an array as the method's target // object. COMPILE_ASSERT( internal::HasIsMethodTag<RunnableType>::value || !internal::NeedsScopedRefptrButGetsRawPtr<P1>::value, p1_is_refcounted_type_and_needs_scoped_refptr); COMPILE_ASSERT(!internal::HasIsMethodTag<RunnableType>::value || !is_array<P1>::value, first_bound_argument_to_method_cannot_be_array); typedef internal::BindState<RunnableType, RunType, void(typename internal::CallbackParamTraits<P1>::StorageType)> BindState; return Callback<typename BindState::UnboundRunType>( new BindState(internal::MakeRunnable(functor), p1)); }
可以看出来主要做了三件事情:
1.调用internal::MakeRunnable创建了一个RunnableAdapter对象。
2.调用BindState的构造函数,传入两个参数分别为RunnableAdapter对象,p1。
3.由BindState对象构造一个Callback对象。
其中MakeRunnable实现如下代码所示:
template <typename T> typename FunctorTraits<T>::RunnableType MakeRunnable(const T& t) { return RunnableAdapter<T>(t); }
从中我们就可以知道,Chromium里面的Callback机制实际上就是预先通过一系列预定义的C++模板类和C++模板函数来实现的,使得我们可以将一些预先指定的参数和函数绑定在一个BindState对象和一个RunnableAdapter对象中,并且封装在一个Callback对象中,最后以Callback类的成员函数Run作为统一的调用接口来间接地调用预先绑定的函数,并且将预先指定的参数以及调用Callback类的成员函数Run指定的参数传递给它。
这种Callback机制适合用作线程间异步通信。假设有两个线程A和B,其中线程A希望在线程B中执行一个任务。这时候线程A就可以将该任务封装成一个Callback对象,并且将该Callback对象发送到线程B的任务队列去。于是线程B调度该Callback对象时,不需要知道它描述的是一个什么样的任务,只需要统一地调用它的成员函数Run,就可以让它执行一个具体的任务。
Chromium将这种用于线程间异步通信的Callback对象称为Closure对象,如下所示:
typedef Callback<void(void)> Closure;
这意味着一个Closure对象是这样的一个Callback对象:
1.被调用的函数,以及调用该函数时使用的所有参数,都必须预先指定,也就是不能在调用时指定。
2. 被调用的函数的返回值为void。
满足上述条件的Callback对象就称为Closure对象,也就是Chromium多线程通信的Closure机制
相关文章推荐
- Chromium扩展(Extension)通信机制分析
- Chromium 多线程机制分析
- Chromium的IPC消息发送、接收和分发机制分析
- Linux下的多线程机制的分析与实现
- Binder与Service 通信机制详解四 (源码分析AIDL工作机制)
- Chromium Graphics: GPUclient的原理和实现分析之间的同步机制-Part I
- Chromium Graphics: GPUclient的原理和实现分析之间的同步机制-Part II
- VxWorks中信号量实现任务间通信与同步机制分析
- Java多线程四:线程间通信/等待唤醒机制
- Android2.2 Vold 分析-(二)---Vold 中 Netlink事件通信机制分析
- Android线程间异步通信机制源码分析
- nginx源码分析1———进程间的通信机制三(mmap)
- Storm进程通信机制分析
- 多线程间通信之AutoResetEvent和ManualResetEvent的原理分析和开发示例
- 一道多线程通信实例分析
- 彻底明白多线程通信机制:
- Storm进程通信机制分析
- Java基础学习5_多线程(线程间通信--等待唤醒机制)
- Android多线程消息处理机制 HandlerThread案例分析
- chromium之extension机制简单分析二:extensionservice创建及初始化