Task
Chrome的线程从实现层面来看没有任何区别,它们的区别只是职责的不同,即处理不同的Task。当期望,一个逻辑在某个线程内执行的时候,可以派生一个Task,把逻辑封装在 Run方法中,然后实例一个对象,调用期望线程中的PostTask方法,将该Task对象放入到其Task队列中去,等待执行。为了统一所有消息循环中的任务调用方式,所有的任务的基类都是这个Task类,他唯一的方法就是run(),MessageLoop只需要调用这个虚函数即可。
什么是Task?
简单的看,Task就是一个类,一个包含了 void Run()抽象方法的类。一个真实的任务,可以派生Task类,并实现其Run方法。每个MessagePump类中,会有一个 MessagePump::Delegate的类的对象(MessagePump::Delegate的一个实现),在这个对象中,会维护若干个Task的队列(输入队列、工作队列、延迟延迟任务队列和需在顶层执行的延迟任务队列)。当你期望,你的一个逻辑在某个线程内执行的时候,你可以派生一个Task,把你的逻辑封装在 Run方法中,然后实例一个对象,调用期望线程中的PostTask方法,将该Task对象放入到其Task队列中去,等待执行。
Chrome在底层库上对task的实现:
1、它提供了一大套的模板封装(参见task.h),可以将Task摆脱继承结构、函数名、函数参数等限制;
2、同时派生出CancelableTask、ReleaseTask、DeleteTask等子类,提供更为良好的默认实现;
3、在消息循环中,按逻辑的不同,将Task又分成即时处理的Task、延时处理的Task、Idle时处理的Task,满足不同场景的需求;
4、Task派生自tracked_objects::Tracked,Tracked是为了实现多线程环境下的日志记录、统计等功能,使得Task天生就有良好的可调试性和可统计性;
如何PostTask?
分发线程的最底层是使用MessageLoop.PostTask和MessageLoop.PostDelayedTask
1、PostTask,发送需要马上进行处理的并且可以在嵌套消息循环中处理的消息。
2、PostDelayedTask,发送需要延迟处理的并且可以在嵌套消息循环中处理的消息。
PostTask会在一个特别的线程上进行一个任务调度。这个任务定义为一个base::Closure,这是base::Callback<void(void)>的一个子类型。PostDelayedTask会在一个特殊线程里,延迟发起一个任务。这个任务由base::Closure类表示,它包含一个Run()方法,并在base::Bind()被调用时创建。处理任务时,消息循环最终会调用base::CLosure的Run函数,然后丢掉对任务对象的引用。任务发向文件线程去处理:
Task的生命周期
PostTask参数决策树 传递绑定的对象如果在一个线程里面需要访问另一个线程的数据,则把接下来要运行的函数和参数包装成一个Task,并将其传递给另外一个线程,由另外一个线程来执行这个Task,从而避免关键数据的并发访问,而又因为任务执行是有顺序的,这样就保证了代码执行的确定性。
线程间taskTask的消息流向?
在Chrome的多线程模型下,同步和异步的编程模型区别就不复存在了,如果是这样一个场景:A线程需要B线程做一些事情,然后回到A线程继续做一些事情;在Chrome下你可以这样来做:生成一个Task,放到B线程的队列中,在该 Task的Run方法最后,会生成另一个Task,这个Task会放回到A的线程队列,由A来执行。
Taskrunner
类的简介
相关成员函数
RunnableMethod
RunnableMethod是一个很非常有用的类,这个方法通过模版将一个对象和他的方法和参数封装成一个Task,抛入另外一个线程去工作,其中为了保证对象的生命周期,对象的指针必须有引用计数,如果这个Task跨线程调用的话,这个引用计数必须是线程安全的。参数则通过Tuple来进行封装。在Task执行的时候通过另外一个模版将Tuple解开成参数即可。
网友评论