重要的抽象和数据结构

这篇博客探讨了Chromium中的重要抽象和数据结构,包括TaskRunner、MessageLoop、SequencedTaskRunner以及SingleThreadTaskRunner等任务调度接口。同时,介绍了base库中的Callback、Bind、RefCounted和LazyInstance等数据类型及其在多线程环境中的使用。还讨论了文件路径处理、ObserverList和WeakPtr等概念。
摘要由CSDN通过智能技术生成

重要的抽象和数据结构

TaskRunnerSequencedTaskRunnerSingleThreadTaskRunner

用于发布由TaskRunner运行的base :: Callbacks“任务”的接口。TaskRunner不保证执行(顺序,并发性,甚至根本不执行)。SequencedTaskRunner提供有关执行顺序的某些保证(大致来说是FIFO,但如果感兴趣,请参见标头中的详细内容),并且SingleThreadTaskRunner提供与SequencedTaskRunner相同的保证,除了所有任务都在同一线程上运行。MessageLoopProxy是SingleThreadTaskRunner的规范示例。这些接口对于通过依赖项注入进行测试也很有用。 注意: 成功发布到TaskRunner并不一定意味着该任务将运行。

注意: TaskRunner的一个非常有用的成员函数是PostTaskAndReply(),该函数会将任务发布到目标TaskRunner,并在完成时将“答复”任务发布到原始TaskRunner。

MessageLoopMessageLoopProxyBrowserThreadRunLoop

这些是用于发布任务的各种API。MessageLoop是MessageLoopProxy(在Chromium代码中使用最广泛的任务运行程序)使用的具体对象。您几乎应该总是使用MessageLoopProxy而不是MessageLoop,或者如果您使用的是chrome或content,则可以使用BrowserThread。这是为了避免在破坏MessageLoop方面发生争执,因为如果基础MessageLoop已被破坏,则MessageLoopProxy和BrowserThread将删除该任务。 注意: 成功发布到MessageLoop(Proxy)不一定意味着任务将运行。

PS:关于何时使用SequencedTaskRunner,MessageLoopProxy和BrowserThread,存在一些争论。使用诸如SequencedTaskRunner之类的接口类可使代码更加抽象/可重用/可测试。另一方面,由于额外的间接层,它使代码不那么明显。尽管可以说您可以适当地命名SequencedTaskRunner变量以使其更加清晰,但使用具体的BrowserThread ID可以立即清楚地知道它在哪个线程上运行。当前的决定是仅在必要时将代码从BrowserThread转换为TaskRunner子类型。MessageLoopProxy应该始终作为SingleThreadTaskRunner或父接口(如SequencedTaskRunner)传递。

base :: SequencedWorkerPoolbase :: WorkerPool

这是Chromium中的两个主要工作人员池。SequencedWorkerPool是一个更复杂的工作池,它继承自TaskRunner,并提供了按顺序排序任务的方式(通过共享SequenceToken),并且还指定了关闭行为(阻止执行任务,如果浏览器正在关闭,则不要运行该任务,并且它尚未启动,但是否已阻止它,或者允许该任务运行,而与浏览器关闭无关,也不要阻止它关闭)。SequencedWorkerPool还提供了一种基于SequenceToken返回SequencedTaskRunner的功能。在所有主浏览器线程(主线程除外)都停止之后,Chromium浏览器进程将关闭base :: SequencedWorkerPool。base :: WorkerPool是一个全局对象,不会在浏览器进程关闭时关闭,因此它上运行的所有任务都不会加入。通常不建议使用base :: WorkerPool,因为任务可能依赖于其他对象,这些对象可能会在浏览器关闭期间被销毁。

base :: Callbackbase :: Bind()

base :: Callback是一组内部引用的模板化回调类,它们具有不同的Arities和返回值(包括void)。请注意,这些回调是可复制的,但共享(通过refcounting)函数指针和绑定参数的内部存储。base :: Bind()将把参数绑定到一个函数指针(在幕后,它将函数指针和所有参数复制到内部引用存储对象中)并返回base :: Callback。

如果函数是成员函数,则base :: Bind()会自动将第一个参数添加到AddRef()/ Release(),如果未重新引用类型,它将抱怨(避免base :: WeakPtr或base :: Unretained()出现此问题) )。同样,对于函数参数,它将使用COMPILE_ASSERT尝试验证它们是否不是指向refcounted类型的原始指针(仅在具有完整类型信息的情况下才可用,而不在前向声明中)。而是使用scoped_refptrs或调用make_scoped_refptr()来防止bug。另外,base :: Bind()理解base :: WeakPtr。如果函数是成员函数,并且第一个参数是对象的base :: WeakPtr,则base :: Bind()将注入包装器函数,仅当base :: WeakPtr为非NULL时才调用函数指针。base :: Bind()还具有以下用于参数的辅助包装器。

  • base :: Unretained()-禁用成员函数接收器对象(可能不是refcounted类型)和函数参数上的COMPILE_ASSERT的refcounting。请谨慎使用,因为这意味着您需要确保对象的生存期可以超过调用回调的时间。对于成员函数接收者对象,最好改用base :: WeakPtr。
  • base :: Owned()-将原始指针的所有权转移到返回的base :: Callback存储中。这非常有用,因为不能保证TaskRunners在关闭时运行回调(可能要删除对象),因此通过使回调拥有所有权,可以防止在不运行回调时烦人的关闭泄漏。
  • base :: Passed()-用于将范围对象(scoped_ptr / ScopedVector / etc)传递给回调。base :: Owned()和base :: Passed()之间的主要区别是base :: Passed()要求函数签名将范围类型作为参数,从而允许 通过.release()转移所有权。注意: 由于范围类型的范围是函数范围,因此这意味着base :: Callback只能被调用一次。否则,这将是潜在的使用,可能需要经过免费删除和一定的两次删除。与base :: Owned()相比,鉴于base :: Passed()的语义复杂性, 一般而言,您应该更喜欢base :: Owned()而不是base :: Passed()
  • base :: ConstRef()-将参数作为const引用传递,而不是将其复制到内部回调存储中。出于明显的性能原因很有用,但通常不应使用,因为它要求引用的生存期必须超过可以调用回调的时间。
  • base :: IgnoreResult()-将其与传递给base :: Bind()的函数指针一起使用,以忽略结果。使回调可与仅使用闭包的TaskRunner一起使用(无参数或返回值的回调)很有用。

scoped_refptr 和base :: RefCounted和base :: RefCountedThreadSafe

引用计数有时是有用的,但通常更表示有人没有仔细考虑所有权。当所有权真正共享时(例如,多个选项卡共享同一个渲染器进程),而不是 在难以进行寿命管理的情况下,可以使用它。

单例base :: LazyInstance

它们是全局变量,因此按照样式指南,通常应避免使用它们。就是说,当您在Chromium代码中使用全局变量时,通常最好使用其中之一,通常,与Singleton相比,更喜欢使用base :: LazyInstance。使用这些类的原因是构造是懒惰的(因此可以防止由于静态初始化程序而导致启动减慢),并且销毁顺序是明确定义的。销毁AtExitManager时,销毁它们的顺序与构造顺序相反。在Chromium浏览器过程中,AtExitManager早在主线程(UI线程)中实例化,因此,即使在不同的线程上构建,所有这些对象也会在主线程上被销毁。选择base :: LazyInstance而不是base :: Singleton的原因是base :: LazyInstance通过保留数据段中的空间并使用new放置在该内存位置中构造对象来减少堆碎片。注意: Singleton和base :: LazyInstance都提供“泄漏”特征以在关闭时泄漏全局变量。通常建议这样做(可能在库代码中除外,在库代码中可能会将代码动态加载到另一个进程的地址空间中,或者在进程关闭时需要刷新数据时),以免减慢关闭速度。对于这些“泄漏”特征,有valgrind抑制。

base :: Threadbase :: PlatformThread

通常,您不应该使用这些功能,因为您通常应该将任务发布到现有TaskRunner上。PlatformThread是特定于平台的线程。base :: Thread包含在PlatformThread上运行的MessageLoop。

base :: WeakPtrbase :: WeakPtrFactory

通常是线程不安全的弱指针,如果引用已被销毁,则返回NULL。跨线程传递(并在其他线程上销毁)是安全的,但只应在创建该线程的原始线程上使用。base :: WeakPtrFactory非常适合在base :: WeakPtr的引用被销毁时自动取消base :: Callbacks。

文件路径

文件路径的跨平台表示。通常,您应该使用它代替特定于平台的表示形式。

ObserverListObserverListThreadSafe

ObserverList是一个线程不安全的对象,旨在用作类的成员变量。它提供了一个简单的接口,用于迭代一堆Observer对象并调用通知方法。

ObserverListThreadSafe类似。它包含多个ObserverLists,并且在注册观察者的同一PlatformThreadId上调用观察者通知,从而允许跨线程代理通知,并允许各个观察者以单线程方式接收通知。

泡菜

Pickle提供了二进制形式的对象序列化和反序列化的基本工具。

值允许指定包含简单值(bool / int / string / etc)的递归数据类(列表和字典)。这些值也可以序列化为JSON并返回。

日志

这是登录Chromium的基本接口。

FileUtilProxy

通常,您不应该在对垃圾邮件敏感的线程(BrowserThread :: UI和BrowserThread :: IO)上执行文件I / O,因此您可以通过这些实用程序将它们代理到另一个线程(例如BrowserThread :: FILE)。

时间 TimeDelta TimeTicks计时器

通常使用TimeTicks而不是Time来保持稳定的滴答计数器(如果用户更改计算机时钟,则时间可能会更改)。

PrefServiceExtensionPrefs

与用户Profile关联的持久状态的容器。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值