在前面,我们学习了content_shell的流程,串成了一条执行线。从今天开始,我们要开始学习线上的点,由点延伸成为面,最后组成一个学习chromium的网。
首先,我们先介绍chromium中的thread相关知识。
chromium中有哪些线程呢?
1. UI线程。应用程序起来后的主线程。
2. IO线程。负责browser进程和子进程之间的调度线程
3. file线程。不解释
4. db线程。不解释
5. safe_browsing线程。不清楚
chromium关于thread的设计原则有两个:1. 不阻塞UI线程,使得UI有更好的响应。2.不鼓励加锁机制和线程安全对象。
如何做到的呢?那就要考虑chromium中的线程模型了。
1. 不在UI线程作阻塞IO操作,不在IO线程作阻塞IO操作。
2. 线程之间不互相阻塞
3. 许多API都是异步的
为了避免加锁机制,chromium提供的thread模型是在每个线程内保留消息循环,线程之间通过消息传递任务,处理回调函数。
关于多线程的加锁,摘抄如下一段话
多线程编程一直是一件麻烦的事情,线程执行的不确定性,资源的并发访问,一直困扰着众多程序员们。为了解决多线程编程的麻烦,大家想出了很多经典的方案:如:对资源直接加锁,角色模型,CSP,FP等等。他们的思想基本分为两类:一类是对存在并发访问资源直接加锁,第二类是避免资源被并发访问。前者存在许多问题,如死锁,优先级反转等等,而相对来说,后者会好很多,角色模型,CSP和FP就都属于后者,Chrome也是使用后者的思想来实现多线程的。
从开发的角度,我们该如何使用chromium提供的这种线程模型呢?
提供模板类base::Callback<>,该类有一个Run函数。其作为函数指针泛型,由base::Bind产生。废话少说,看个例子就什么都明白了
void ReadToString(const std::string& filename, const base::Callback<void(const std::string&)>& on_read); void DisplayString(const std::string& result) { LOG(INFO) << result; } void SomeFunc(const std::string& file) { ReadToString(file, base::Bind(&DisplayString)); };
解释:base::Bind把函数指针 &DisplayString 转化为 base::Callback<void(const std::string& result)>。参数部分请参考
柯里化
如何往一个线程里面放任务呢?
chromium提供的线程模型里面提供PostTask,PostDelayedTask方法。我们以PostTask为例。
void MessageLoop::PostTask( const tracked_objects::Location& from_here, const base::Closure& task) 其中, typedef Callback<void(void)> Closure;
因此,可以看到如下一个简单的例子
void WriteToFile(const std::string& filename, const std::string& data); BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind(&WriteToFile, "foo.txt", "hello world!"));
如何让一个类成员函数作为task呢?
同样的道理,只是第一个参数变为类对象。如下例子,不过注意对象通常是引用计数的。
class MyObject : public base::RefCountedThreadSafe<MyObject> { public: void DoSomething(const std::string16& name) { thread_->message_loop()->PostTask( FROM_HERE, base::Bind(&MyObject::DoSomethingOnAnotherThread, this, name)); } void DoSomethingOnAnotherThread(const std::string16& name) { ... } private: // Always good form to make the destructor private so that only RefCountedThreadSafe can access it. // This avoids bugs with double deletes. friend class base::RefCountedThreadSafe<MyObject>; ~MyObject(); Thread* thread_; };
注意:base::bind中的参数会被复制到内部存储结构。
未完成,继续!!!
以下的参考很不错。第一个是我本文的主要来源,或者说翻译了部分精华内容。第二个从源码的角度分析了thread。第三个就从实现的角度讲解。
参考:
1. http://www.chromium.org/developers/design-documents/threading