进程
主进程
- Browser进程
- 与用户交互的界面
渲染进程
- Renderer进程
- 解析html,css,执行javascript脚本
GPU进程
- 负责网页和主界面的绘制
Utility进程
- 各种服务,如网络服务,音频服务
V8代理解析工具进程
- 跑PAC代理脚本时的进程
Crashpad-handler进程
- 奔溃处理进程
Ppapi进程
- ppapi插件的进程
进程模式
- 浏览器提供了4种进程模式,如下。
single process
- 只有browser进程,没有renderer进程
- 所有工作都在browser进程里运行
process-per-tab
- 一个tab对应一个renderer进程
process-per-site
- 每个域名使用一个renderer进程
process-per-site-instance
- 每个域名实例使用一个renderer进程
线程
Browser进程中的线程
- 主线程
- 浏览器进程中的
- BrowserThread::UI
- 负责更新用户界面,响应用户操作
- 渲染器进程中的
- 运行大多数Blink
- 浏览器进程中的
- IO线程
- 浏览器进程中的
- BrowserThread::IO
- 负责处理IPC和网络请求
- 渲染器进程中的
- 处理IPC
- 浏览器进程中的
- 线程池里的若干线程
- 一些特殊目的的线程
所谓物理线程
- Thread
- 操作系统提供的线程,可以使用base::Thread创建,但是没必要创建
- 两个task先后Post到同一个Thread上,那么这两个task一定会在同一个物理线程上,以post的顺序先后执行
所谓虚拟线程
- Sequence
- 由Chrome维护的虚拟线程
- 两个task先后Post到同一个Sequence上,那么这两个task可能会在同一条物理线程上执行,也可能在不同的物理线程执行,但是执行顺序一定跟post顺序一致的
- 如果不是跟UI相关,尽量使用Sequence,比如去后台Load一个大文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
class MyView { public: MyView() { //创建Squence task_runner_ = ...; //将sequence_checker_与当前Sequence脱离绑定 DETACH_FROM_SEQUENCE(sequence_checker_); } void Load() { //Post到task_runner_ Squence中执行 task_runner_->PostTask(FROM_HERE, base::BindOnce(&MyView::LoadImpl, base::Unretained(this))); } private: void LoadImpl() { //检查是不是在task_runner_ Squence调用 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); //加载 Data data = ...; //Post到UI线程 base::PostTask(FROM_HERE, {content::BrowserThread::UI}, base::BindOnce(&MyView::LoadComplete, base::Unretained(this), std::move(data))); } void LoadComplete(Data data) { //检查是不是在UI线程中调用 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); } private: scoped_refptr<SequencedTaskRunner> task_runner_; SEQUENCE_CHECKER(sequence_checker_); }; |
SEQUENCE_CHECKER
/DCHECK_CALLED_ON_VALID_SEQUENCE
使用来检查函数有没有在指定的Squence中运行的。
如果需要检查有没有在指定的线程运行,可以用THREAD_CHECKER
/DCHECK_CALLED_ON_VALID_THREAD
1 2 |
THREAD_CHECKER(thread_checker_); DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); |
可调用对象
介绍
- BindRepeating返回RepeatingCallback函数对象
- BindOnce返回OnceCallback函数对象
- 区别是RepeatingCallback以调用多次,而OnceCallback则只能调用一次
1 2 3 4 5 6 7 8 9 10 11 12 |
void Foo() { std::cout << "hello world." << std::endl; } base::RepeatingCallback<void()> a = base::BindRepeating(&Foo); a.Run(); // 正确,输出Hello, world a.Run(); // 正确,再次输出Hello, world base::OnceCallback<void()> b = base::BindOnce(&Foo); b.Run(); // 错误,编译报错 std::move(b).Run(); //正确,输出Hello, world std::move(b).Run(); //错误,前一次调用已经将b置为空 |
别名
1 2 3 4 |
using Bind = BindRepeating; using Callback = OnceCallback; using Closure = RepeatingCallback<void()>; using OnceClosure = OnceCallback<void()>; |
Task
- 一个task是一个被放到一个异步执行的队列中的
base::OnceClosure
base::OnceClosure
存储了函数指针和参数,它有一个方法Run(),Run可以通过绑定的参数启动这个函数指针,可以使用base::BindOnce
来创建一个base::OnceClosure
- 跟std::bind比起来,Chromium的
base::Bind
语法上更加简洁 - 提供了参数生命周期的管理
stl
1 |
auto func = std::bind(&MyView::ReadConf, this, _1); |
chrome
1 2 3 |
auto task = base::Bind(&MyView::ReadConf, GetWeakPtr()); auto task = base::BindOnce(&MyView::ReadConf, GetWeakPtr()); |
运行方式
对于一组task来说:
并行任务
- 对于可以同时运行在任何线程上,且不用在意执行的顺序的任务或不会与其他任务有互斥需求的任务。
1 |
base::ThreadPool::PostTask(FROM_HERE, base::BindOnce(&Task)); |
有序任务
- 任务按发布的顺序执行,在任何线程上一次执行
1 2 3 4 5 6 |
scoped_refptr<SequencedTaskRunner> sequenced_task_runner = base::ThreadPool::CreateSequencedTaskRunner(...); // TaskB runs after TaskA completes. sequenced_task_runner->PostTask(FROM_HERE, base::BindOnce(&TaskA)); sequenced_task_runner->PostTask(FROM_HERE, base::BindOnce(&TaskB)); |
单线程
- 任务按发布的顺序执行,在单一线程上一次执行
- 多个任务如果需要运行在相同的线程上,需要发布到
base::SingleThreadTaskRunner
任务优先级和其他参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// 能获得的最低优先级 base::TaskPriority::LOWEST // 优先级和LOWEST是一样的低 当所需的机器资源可获得时 BEST_EFFORT = LOWEST, // 不会对用户交互后立即影响UI USER_VISIBLE // 用户阻塞任务会在用户交互后立即影响UI USER_BLOCKING // 能获得的最高优先级 HIGHEST = USER_BLOCKING |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
// 没有提供显式的TaskTraits,不会阻塞,优先级是USER_BLOCKING, base::ThreadPool::PostTask(FROM_HERE, base::BindOnce(&Task)); // 下面这个任务的优先级最高,线程池将会优先于USER_VISIBLE和BEST_EFFORT来调度它 base::ThreadPool::PostTask( FROM_HERE, {base::TaskPriority::USER_BLOCKING}, base::BindOnce(...)); // 下面这个任务的优先级最低,被允许阻塞 base::ThreadPool::PostTask( FROM_HERE, {base::TaskPriority::BEST_EFFORT, base::MayBlock()}, base::BindOnce(...)); // 下面这个任务会阻塞住,在任务完成之前,进程不会退出 base::ThreadPool::PostTask( FROM_HERE, {base::TaskShutdownBehavior::BLOCK_SHUTDOWN}, base::BindOnce(...)); // 允许调用者通过TaskTraits对任务提供更多的描述 base::ThreadPool::PostTask( FROM_HERE, {base::TaskPriority::BEST_EFFORT, MayBlock()}, base::BindOnce(&Task)); |
生命周期
GetWeakPtr()
- 持有该类对象的一个弱引用
- Run内部会检查weak_ptr_factory_的有效性
- 如果已经失效,会放弃调用并之间返回
- 相比之下更安全,但需要额外的空间保存这个weak_ptrfactory
- WeakPtr不能跨线程,因此不能将上述实例中的task post到别的线程中去调用。如果执意将上述task post到了别的线程中调用了,表面上是触发了DCHECK,实际上是在没有加锁的情况下,在两个线程中访问这个weak_ptrfactory
1 2 3 4 |
base::WeakPtrFactory<ContentView> weak_ptr_factory_{this}; delete this; auto task = base::BindOnce(&MyView::ReadConfig,weak_ptr_factory_.GetWeakPtr()); task.Run(); // 不会崩溃 |
base::Owned()
- 让对应的Callback函数对象持有参数
- 当callback被Reset或者析构时,会同时delete掉持有的对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
int* p = new int(); auto my_callback = base::Bind(&MyFunction, base::Owned(p)); *p = 10; //Ok my_callback.Run(); *p = 20; //Ok my_callback.Reset(); *p = 30; //出错,p指向的内存已经被delete //----------------- int* p = new int(); auto my_callback = base::BindOnce(&MyFunction, base::Owned(p)); *p = 10; //Ok std::move(my_callback).Run(); *p = 20; //出错,p指向的内存已经被delete |
base::RetainedRef()
- RetainedRef是给智能指针scoped_refptr对象增加引用计数
- base::RetainedRef(p)会增加p的引用计数,以确保函数对象在销毁前,p指向的对象不会被析构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
class MyFoo : public RefCounted<MyFoo> { //必须继承RefCounted才能使MyFoo支持scoped_refptr //... private: friend class RefCounted<MyFoo>; ~MyFoo(); }; void MyFunction(MyFoo*) {} //... scoped_refptr<MyFoo> p = MakeRefCounted<MyFoo>(); auto my_callback = base::Bind(&MyFunction, base::RetainedRef(p)); p.reset(); //p释放,但是MyFoo对象不销毁 my_callback.Run(); //Ok my_callback.Reset();//my_callback置空,MyFoo对象引用计数为0,并将MyFoo对象销毁 |
- 如果传
scoped_prefptr<MyFoo>
不使用RetainedRef(如下)怎么样?- 编译器会将scoped_refptr隐式转换成MyFoo*指针,然后编译失败。
1 2 |
scoped_refptr<MyFoo> p = MakeRefCounted<MyFoo>(); auto my_callback = base::Bind(&MyFunction, p); |
base::Unretained(this)
- 如果要使用的类支持scoped_refptr,那么可以使用base::RetainedRef(this)
- 如果要使用的类支持WeakPtr,那么可以使用this->GetAsWeakPtr();
- 如果两者都不支持,就只能用Unretained了,Unretained是既不持有,也不增加引用计数,相当于传裸指针。
1 2 3 4 5 6 7 8 9 10 |
class MyFoo { void OnLoadComplete() {} }; auto load_callback = base::Bind(&MyFoo::OnLoadComplete, base::Unretained(this)); delete this load_callback.Run(); //崩溃 //如果不是使用base::Unretained会怎么样呢? base::Bind(&MyFoo::OnLoadComplete, this); //编译出错,并提示MyFoo does not support the AddRef() and Release() methods |
base::Passed()
- Passed主要是为base::BindRepeating设计的
- 当使用
BindRepeating
的时候如果需要传入unique_ptr参数的时候需要使用Passed - 而对于
BindOnce
在传入unique_ptr的时候,只需要使用std::move()
即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
void Foo(std::unique_ptr<int> p) { if (p) { printf("Dog"); } else { printf("Cat"); } } std::unique_ptr<int> a(new int(10)); auto a_call = base::BindRepeating(&Foo, std::move(a)); //编译错误,对于base::BindRepeating,使用std::move(a)触发static_assert std::unique_ptr<int> b(new int(10)); auto b_call = base::BindOnce(&Foo, std::move(b)); //编译正常,对于base::BindOnce使用std::move即可完成转移 std::unique_ptr<int> c(new int(10)); auto c_call = base::BindRepeating(&Foo, base::Passed(&b)); //编译正常,base::Passed(b)完成转移,另外换成base::Passed(std::move(b))也可以 c_call.Run();//输出Dog c_call.Run();//引发异常 //连续两次调用c_call.Run分别输出Dog和Cat //第一次调用时,unique_ptr的内容从c_call转移到Foo的参数p上,因此输出Dog,调用完毕后,Foo的参数p销毁 //第二次调用时,触发异常,而不是输出Cat |
std::move()
- std::move使用转移语义传递参数,以避免对象拷贝。
1 2 3 4 5 6 7 8 9 |
class MyFoo { public: void Hello(std::string str) {} }; MyFoo* foo = new MyFoo(); std::string desc = "my name is liebao browser" base::Bind(&MyFoo::Bar, base::Unretained(foo), std::move(desc)); printf(desc.c_str()) // 输出为空,desc已经被move到函数对象中 |
PostTask
1 2 3 |
bool base::PostTask(const Location& from_here, const TaskTraits& traits, OnceClosure task); |
Task Post到UI线程中
1 2 |
base::TaskTraits traits = {content::BrowserThread::UI}; PostTask(FROM_HERE, traits, std::move(task)); |
Task Post到线程池中的某个线程
1 2 |
base::TaskTraits traits = {base::TaskPriority::BEST_EFFORT, MayBlock()}; PostTask(FROM_HERE, traits, std::move(task)); |
Task1 Post到别的线程中,再回到原来的线程执行Task2
1 2 3 4 |
PostTaskAndReply(FROM_HERE, traits, std::move(task1), std::move(task2)); |
Task1 Post到别的线程中,再回到原来的线程执行Task2(把task1的结果作为参数传给task2)
1 2 3 4 |
PostTaskAndReplyWithResult(FROM_HERE, traits, std::move(task1), std::move(task2)); |
创建或从线程池中取一条真实线程,往这个线程Post Task
- 往线程池中同一个线程中post task
1 2 3 4 5 |
scoped_refptr<SingleThreadTaskRunner> task_runner = base::ThreadPool::CreateSingleThreadTaskRunner(traits); task_runner->PostTask(FROM_HERE, std::move(task1)); task_runner->PostTask(FROM_HERE, std::move(task2)); |
创建一个虚拟线程,往这个线程中Post Task
1 2 3 4 5 |
scoped_refptr<SequencedTaskRunner> task_runner = base::ThreadPool::CreateSequencedTaskRunner(traits); task_runner->PostTask(FROM_HERE, std::move(task1)); task_runner->PostTask(FROM_HERE, std::move(task2)); |
本文为原创文章,版权归Aet所有,欢迎分享本文,转载请保留出处!