• 忘掉天地
  • 仿佛也想不起自己
bingliaolongBingliaolong  2021-09-03 13:15 Aet 隐藏边栏 |   抢沙发  28 
文章评分 2 次,平均分 5.0

closure

  1. Chromium多线程通信用到的Closure实际上是一个特殊的Callback。

  1. 如果把上面创建的Callback对象看作是一个Closure,那么它首先会被发送到目标线程的消息队列中,然后再在目标线程中调用它的成员函数Run,最后就会导致函数MyFunc在目标线程中被调用。
  2. Callback对象还可以与一个类的成员函数绑定,如下:
    这里绑定的类对象就为myclass,并且是以裸指针的形式指定的。这时候我们就需要保证Callback对象cb的成员函数Run被调用时,对象myclass还没有被销毁。

  1. 为了更方便地管理被绑定对象的生命周期,函数base::Bind允许通过scoped_refptr智能指针来绑定类对象,如下:
    Callback对象cb使用完成之后,对象myclass会自动释放,这样就可以保证Callback对象cb的成员函数Run被调用时,对象myclass是存在的。
    也可以通过函数GetWeakPtr获得对象myclass的一个WeakPtr弱智能指针,这样当Callback对象cb的成员函数Run被调用时,如果对象myclass已经被销毁,那么就不会调用它的成员函数MyFunc。

callback

  1. Callback类是从CallbackBase类继承下来的。CallbackBase类有两个成员变量bind_state_和polymorphicinvoke
    1. bind_state_指向的是一个BindState对象,该BindState对象是保存了其宿主Callback对象创建时绑定的函数以及参数。
    2. polymorphic_invoke_指向的是一个InvokeFuncStorage对象,该InvokeFuncStorage对象描述的是Invoker类的静态成员函数Run。
  2. BindState类是从BindStateBase类继承下来的,BindStateBase类又是从RefCountedThreadSafe类继承下来的。可以配合智能指针来使用。
  3. BindState类将宿主Callback对象创建时绑定的参数保存在成员变量p1_、p2_等中,绑定的函数则保存在成员变量runnable_指向的一个RunnableAdapter对象的成员变量function_中。
  4. 当CallbackBase类的成员函数Run被调用时,它们通过成员变量polymorphic_invoke_调用Invoker类的静态成员函数Run。
  5. Invoker类的静态成员函数Run从BindState对象分别取出与它绑定的参数p1_、p2_等,以及RunnableAdapter对象,连同传递给CallbackBase类的成员函数Run的参数,一起再传递给InvokeHelper类的静态成员函数MakeItSo。
  6. InvokeHelper类的静态成员函数MakeItSo接下来又会调用传递给它的RunnableAdapter对象的成员函数Run,后者又会调用保存在其成员变量function_的函数,这时候调用的实际上就是其关联的Callback对象绑定的函数。

多线程模型

概述

  1. 线程经过短暂的启动之后(Start),就围绕着一个任务队列(TaskQueue)不断地进行循环,直到被通知停止为止(Stop)。
  2. 在围绕任务队列循环期间,它会不断地检查任务队列是否为空。如果不为空,那么就会将里面的任务(Task)取出来,并且进行处理。
    这样,一个线程如果要请求另外一个线程执行某一个操作,那么只需要将该操作封装成一个任务,并且发送到目标线程的任务队列去即可。
  3. Thread是一个用来创建带消息循环的类。当我们创建一个Thread对象后,调用它的成员函数Start或者StartWithOptions就可以启动一个带消息循环的线程。

thread

  1. Thread类继承了PlatformThread::Delegate类,并且重写了它的成员函数ThreadMain(跨平台)。
  2. Thread类有一个重要的成员变量messageloop\,它指向的是一个MessageLoop对象。
  3. 这个MessageLoop对象就是用来描述线程的消息循环的。
  4. MessageLoop类内部通过成员变量run_loop_指向的一个RunLoop对象和成员变量pump_指向的一个MessagePump对象来描述一个线程的消息循环。
  5. 一个线程在运行的过程中,可以有若干个消息循环,也就是一个消息循环可以运行在另外一个消息循环里面。除了最外层的消息循环,其余的消息的消息循环称为嵌套消息循环。
  6. RunLoop类有三个重要的成员变量:
    1. messageloop\,记录一个RunLoop对象关联的MessageLoop对象。
    2. previousloop\,记录前一个消息循环,当就是包含当前消息循环的消息循环。
    3. rundepth\,记录消息循环的嵌套深度。
  7. MessageLoop类的成员变量pump_指向的一个MessagePump对象是用来进行消息循环的,也就是说,Thread类描述的线程通过MessagePump类进入到消息循环中去。
  8. Thread类将消息划分为三类
    1. workqueue,指向一个TaskQueue对象,用来保存那些需要马上处理的消息。
    2. delayed_workqueue,指向一个DelayedTaskQueue,用来保存那些需要延迟一段时间再处理的消息。
    3. deferred_non_nestable_workqueue,指向一个TaskQueue对象,用来保存那些不能够在嵌套消息循环中处理的消息。
  9. 一个MessagePump对象在进行消息循环时,如果发现消息队列中有消息,那么就需要通知关联的MessageLoop对象进行处理。通知使用的接口就通过MessagePump::Delegate类来描述。
    1. DoWork,用来通知MessageLoop类处理其成员变量work_queue_保存的消息。
    2. DoDelayedWork,用来通知MessageLoop类处理其成员变量delayed_work_queue_保存的消息。
    3. DoIdleWork,用来通知MessageLoop类当前无消息需要处理,MessageLoop类可以利用该间隙做一些Idle Work。
    4. GetQueueingInformation,用来获取MessageLoop类内部维护的消息队列的信息,例如消息队列的大小,以及下一个延迟消息的处理时间。
  10. Thread类的成员函数StartWithOptions首先是将线程启动参数封装一个在栈上分配的StartupData对象中,并且这个StartupData对象的地址会保存在Thread类的成员变量startup_data_中。接下来再调用由平台实现的PlatformThread类的静态成员函数Create创建一个线程。
    最后通过StartupData对象的成员变量event描述的一个WaitableEvent对象等待上述创建的线程启动完成。
    当新创建的线程启动完成之后,就会通过上述的WaitableEvent对象唤醒当前线程,当前线程将Thread类的成员变量startup_data_置为NULL,避免它引用一个即将无效的在栈上分配的StartupData对象,并且将Thread类的成员变量started_的值设置为true,表示新创建的线程已经启动完毕。

消息循环

  1. MessageLoop类的成员函数Init中,创建了一个任务队列,并且保存在成员变量incoming_queue_中。
    任务队列是一个IncomingQueue类。

  1. IncomingQueue类有两个重要的成员变量:
    1. incomingqueue,它描述的是一个TaskQueue,代表的是线程的消息队列,也就是所有发送给线程的消息都保存在这里。
    2. messageloop,它指向一个MessageLoop对象,描述的是线程的消息循环。
  2. 消息贲类型:
    1. 类型为MessageLoop::TYPE_UI的消息循环对应的消息泵为MessagePumpForUI。
      在Chromium中,消息循环类型为MessageLoop::TYPE_UI的线程称为UI线程,也就是应用程序的主线程。
    2. 类型为MessageLoop::TYPE_IO,那么对应的消息泵为MessagePumpForIO。
      在Chromium中,消息循环类型为MessageLoop::TYPE_IO的线程称为IO线程,但是这里的IO不是读写文件的意思,而是执行IPC的意思。
    3. 其他类型
  3. 消息循环的层次关系
    1. 一个MessageLoop对象的成员函数RunHandler进入消息循环前后,RunLoop类的成员函数Run分别调用了BeforeRun和AfterRun两个成员函数,目的就是为了建立好消息循环的层次关系。

WaitableEvent

  1. WaitableEvent是有效地实现线程消息循环的一个重要类。通过WaitableEvent类,线程可以在无消息处理时进入睡眠状态,并且在有消息处理时从睡眠状态唤醒过来,从而避免了不断地轮循消息队列是否有消息处理的操作。因为消息队列可能在大多数情况下都是空的,对它进行不断轮循将会浪费CPU周期。

向一个线程的消息队列发送消息

  1. MessageLoop类的成员函数PostTask、PostDelayedTask、 PostNonNestableTask和PostNonNestableDelayedTask实现的。

本文为原创文章,版权归所有,欢迎分享本文,转载请保留出处!

bingliaolong
Bingliaolong 关注:0    粉丝:0 最后编辑于:2021-11-19
Everything will be better.

发表评论

表情 格式 链接 私密 签到
扫一扫二维码分享