在前面介绍的Chrome Task类,可以让代码在指定线程上运行。 另一种常见的场景就是发出一个异步请求,并想知道请求处理的结果。这时请求的处理过程虽然是在另一个线程上的,但是请求的结果却从(调用者)请求发起的线程上回来,并且请求是可以取消的。 这是很有用的,比如我们经常从界面上(UI线程)发起一个动作,该动作会在Worker线程执行,结束后会通过回调函数回来。这时的回调函数是运行在Work线程上的,直接操作界面是不行的(比如MFC对象就不允许跨线程访问),访问界面的成员变量也可能跟UI线程冲突(这时就必须使用Lock)。 最好呢,我们能转换一下线程,让回调函数在UI线程上运行,这样就可以避免上面说到的问题了。
有了前面的Task基础,我们可以简单设想一下基本的实现方式。 请求发起时,记住当前的线程。然后,在请求完成后,往保存的线程里PastTask让其执行回调函数。 然后,我们来看一下Chrome的实现代码。
使用场景
如下,MyClass对象调用了Frontend 对象的StarRequest方法,参数为some_input1和some_input2,以及回调函数为RequestComplete,callback_consumer_用于跟踪所有发出的请求。一旦MyClass被释放,则未完成的请求就会自动取消了。
class MyClass {
void MakeRequest() {
frontend_service->StartRequest(some_input1, some_input2, callback_consumer_,
NewCallback(this, &MyClass:RequestComplete));
}
void RequestComplete(int status) {
...
}
private:
CallbackConsumer callback_consumer_;
};
Frontend::StartRequest()首先创建一个CancelableRequest对象用于保存回调函数,然后记录该请求对象request和请求者对象consumer,最后是向后台线程放置一个Task(Backend::DoRequest)来处理该请求,参数为request对象,和MyClass传入的some_input1, some_input2参数。这时候,函数返回了,只待结果异步返回了。
class Frontend : public CancelableRequestProvider {
typedef Callback1<int>::Type RequestCallbackType;
Handle StartRequest(int some_input1, int some_input2,
CallbackConsumer* consumer,
RequestCallbackType* callback) {
scoped_refptr<CancelableRequest<RequestCallbackType> > request(
new CancelableRequest<RequestCallbackType>(callback));
AddRequest(request, consumer);
// Send the parameters and the request to the backend thread.
backend_thread_->PostTask(FROM_HERE,
NewRunnableMethod(backend_, &Backend::DoRequest, request,
some_input1, some_input2));
// The handle will have been set by AddRequest.
return request->handle();
}
};
Backend::DoRequest的参数包括了CancelableRequest对象,调用ForwardResult方法即可把结果放回到调用者线程上(即在调用者线程里进行回调)。并且,在执行之前或者执行的过程中可以随时检查请求是否已经取消,如果是则直接退出了。
class Backend {
void DoRequest(
scoped_refptr< CancelableRequest<Frontend::RequestCallbackType> >
request,
int some_input1, int some_input2) {
if (request->canceled())
return;
... do your processing ...
// Depending on your typedefs, one of these two forms will be more
// convenient:
request->ForwardResult(Tuple1<int>(return_value));
// -- or -- (inferior in this case)
request->ForwardResult(Frontend::RequestCallbackType::TupleType(
return_value));
}
};
能够提供CancelableRequest的对象叫做CancelableRequestProvider,其可以跟踪Request的执行。AddRequest方法用于加入一个Request并返回一个Handle,可以用这个Handle取消Request,当Request执行结束也会通过调用RequestCompleted并传入对应的Handle。
class CancelableRequestProvider {
public:
// Identifies a specific request from this provider.
typedef int Handle;
CancelableRequestProvider();
virtual ~CancelableRequestProvider();
// Called by the enduser of the request to cancel it. This MUST be called on
// the same thread that originally issued the request (which is also the same
// thread that would have received the callback if it was not canceled).
void CancelRequest(Handle handle);
protected:
// Adds a new request and initializes it. This is called by a derived class
// to add a new request. The request's Init() will be called (which is why
// the consumer is required. The handle to the new request is returned.
Handle AddRequest(CancelableRequestBase* request,
CancelableRequestConsumerBase* consumer);
// Called by the CancelableRequest when the request has executed. It will
// be removed from the list of pending requests (as opposed to canceling,
// which will also set some state on the request).
void RequestCompleted(Handle handle);
CancelableRequestProvider::AddRequest内部会为request生成一个Handle(其实就是整型数),并通知consumer已经为它创建了一个Request以及对应Handle。同样的,在Request取消和结束的时候,也都会通知consumber。同时,调用request的Init方法完成最后的初始化工作,并传入handle和consumer对象。
CancelableRequestProvider::Handle CancelableRequestProvider::AddRequest(
CancelableRequestBase* request,
CancelableRequestConsumerBase* consumer) {
Handle handle;
{
AutoLock lock(pending_request_lock_);
handle = next_handle_;
pending_requests_[next_handle_] = request;
++next_handle_;
}
consumer->OnRequestAdded(this, handle);
request->Init(this, handle, consumer);
return handle;
}
CancelableRequestConsumer可以作为类的成员变量,这样当对象被释放时,CancelableRequestConsumer自动取消所有进行中的Request,避免回调时崩溃。当然,每次创建一个Request的时候,也需要传入CancelableRequestConsumer对象,这样才能把Request和CancelableRequestConsumer进行绑定。SetClientData和GetClientData可以给每个Request绑定一个数据(类型为T),这样当Request结束和取消的时候就可以比较容易的知道上下文。
class CancelableRequestConsumerBase {
protected:
friend class CancelableRequestProvider;
virtual ~CancelableRequestConsumerBase() {
}
// Adds a new request to the list of requests that are being tracked. This
// is called by the provider when a new request is created.
virtual void OnRequestAdded(CancelableRequestProvider* provider,
CancelableRequestProvider::Handle handle) = 0;
// Removes the given request from the list of pending requests. Called
// by the CancelableRequest immediately after the callback has executed for a
// given request, and by the provider when a request is canceled.
virtual void OnRequestRemoved(CancelableRequestProvider* provider,
CancelableRequestProvider::Handle handle) = 0;
};
template<class T>
class CancelableRequestConsumerTSimple : public CancelableRequestConsumerBase {
public:
CancelableRequestConsumerTSimple() {
}
// Cancel any outstanding requests so that we do not get called back after we
// are destroyed. As these requests are removed, the providers will call us
// back on OnRequestRemoved, which will then update the list. To iterate
// successfully while the list is changing out from under us, we make a copy.
virtual ~CancelableRequestConsumerTSimple() {
CancelAllRequests();
}
// Associates some random data with a specified request. The request MUST be
// outstanding, or it will assert. This is intended to be called immediately
// after a request is issued.
void SetClientData(CancelableRequestProvider* p,
CancelableRequestProvider::Handle h,
T client_data) {
PendingRequest request(p, h);
DCHECK(pending_requests_.find(request) != pending_requests_.end());
pending_requests_[request] = client_data;
}
// Retrieves previously associated data for a specified request. The request
// MUST be outstanding, or it will assert. This is intended to be called
// during processing of a callback to retrieve extra data.
T GetClientData(CancelableRequestProvider* p,
CancelableRequestProvider::Handle h) {
PendingRequest request(p, h);
DCHECK(pending_requests_.find(request) != pending_requests_.end());
return pending_requests_[request];
}
也可以统一给所有的Request带上一个初值,而不是每次赋值太麻烦。CancelableRequestConsumer则是最简单的,啥都不带的。
template<class T, T initial_t>
class CancelableRequestConsumerT : public CancelableRequestConsumerTSimple<T> {
protected:
virtual T get_initial_t() const {
return initial_t;
}
};
typedef CancelableRequestConsumerT<int, 0> CancelableRequestConsumer;
从CancelableRequestBase我们看到,构造时保留了当前线程的MessageLoop,留着待会儿回调用。
class CancelableRequestBase
: public base::RefCountedThreadSafe<CancelableRequestBase> {
CancelableRequestBase()
: provider_(NULL),
consumer_(NULL),
handle_(0),
canceled_(false) {
callback_thread_ = MessageLoop::current();
}
// Tells the provider that the request is complete, which then tells the
// consumer.
void NotifyCompleted() const {
provider_->RequestCompleted(handle());
}
然后看一下具体实现类,其ForwardResult方法就是把结果放到正确的线程上返回,其实就是PostTask,并在回调完毕后通知Provider说Request已经结束。
template<typename CB>
class CancelableRequest : public CancelableRequestBase {
public:
void ForwardResult(const TupleType& param) {
DCHECK(callback_.get());
if (!canceled()) {
if (callback_thread_ == MessageLoop::current()) {
// We can do synchronous callbacks when we're on the same thread.
ExecuteCallback(param);
} else {
callback_thread_->PostTask(FROM_HERE, NewRunnableMethod(this,
&CancelableRequest<CB>::ExecuteCallback, param));
}
}
}
private:
// Executes the callback and notifies the provider and the consumer that this
// request has been completed. This must be called on the callback_thread_.
void ExecuteCallback(const TupleType& param) {
if (!canceled_) {
// Execute the callback.
callback_->RunWithParams(param);
// Notify the provider that the request is complete. The provider will
// notify the consumer for us.
NotifyCompleted();
}
}
最后,我们来看一下callback_对象,即前面NewCallback(this, &MyClass:RequestComplete)创建的。
template <class T, typename Arg1>
typename Callback1<Arg1>::Type* NewCallback(T* object,
void (T::*method)(Arg1)) {
return new CallbackImpl<T, void (T::*)(Arg1), Tuple1<Arg1> >(object, method);
}
template <class T, typename Method, typename Params>
class CallbackImpl : public CallbackStorage<T, Method>,
public CallbackRunner<Params> {
public:
CallbackImpl(T* obj, Method meth) : CallbackStorage<T, Method>(obj, meth) {
}
virtual void RunWithParams(const Params& params) {
DispatchToMethod(this->obj_, this->meth_, params);
}
};
关于DispatchToMethod,我们已经在讲Task的时候说到了。
在线源码
http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/cancelable_request.h?revision=31932
http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/cancelable_request.cc?revision=32105
分享到:
相关推荐
chrome网页性能分析 教程.zip 统计图 颜色 垃圾回收
关于对话框的显示逻辑位于`about_chrome_view.cc`文件中,该文件定义了一个名为`AboutChromeView`的类,这个类负责关于对话框的显示和交互。通过这个类,我们可以追踪到对话框何时被创建、如何加载资源字符串以及...
Chrome谷歌浏览器源码分析 Chrome浏览器是全球最受欢迎的网络浏览器之一,其强大的性能、安全性和易用性得益于其先进的设计理念和高效的技术实现。本篇将深入探讨Chrome的核心组件——渲染引擎(Rendering Engine)...
主要是对chrome UI的源代码进行分析和相关讲解
该项目是一个基于Chrome扩展的网页词频分析与词云图生成工具,主要使用JavaScript语言开发...这个工具是对chrome-extensions-samples-main项目的改进,采用MIT许可开源,旨在帮助用户分析网站内容的词频并生成词云图。
在标题和描述中提到的"Chrome_autoit操作chrome_autoit3chrome_autoit_autoitchrome_chrome_源",主要涉及到使用AutoIt来控制Google Chrome浏览器。 首先,让我们深入了解一下AutoIt。AutoIt是一个免费的工具,它...
标题中的“谷歌浏览器网页元素分析工具+Chrome_SPY+元素捕获+PRA”涉及到的是在Web开发和调试过程中常用的一些技术与工具。下面将详细解释这些概念。 1. **谷歌浏览器**(Google Chrome):这是一款由谷歌公司开发...
chrome 破解分析chrome 破解分析
cssdig-chrome, 用于分析CSS的Chrome 扩展 CSS挖掘 Chrome安装CSS挖掘为 ChromeCSS挖掘主页这里 Chrome 扩展查找网页上运行的样式表和样式块,并将声明组合在一起,便于检查。 例如你可以看到使用了多少种颜色,以及...
Chrome浏览器是Google开发的一款流行的网页浏览器,以其稳定性和高性能赢得了全球用户的喜爱。版本号99.0.4844.51代表了这个特定版本的Chrome,它可能包含了安全更新、性能优化以及对Web标准的支持增强。"Chrome ...
标题中的“chrome的es插件”指的是在Google Chrome浏览器中使用的Elasticsearch(简称ES)插件。Elasticsearch是一种流行的、开源的全文搜索引擎,常用于大数据分析和实时搜索。这款插件允许用户通过浏览器界面与...
* Chrome 安装失败的原因分析 * Chrome 安装包的组成结构 * 使用压缩程序解压安装包的技巧 结语 本篇文章提供了详细的解决方案,帮助您解决 Chrome 无法安装的问题。同时,我们也提供了一些相关的知识点和概念,...
Chrome UI(用户界面)分析涉及多个层面,包括框架结构、排版绘制机制、消息分发、以及各种UI组件的设计与实现。以下是对Chrome UI分析中的知识点的详细阐述。 首先,Chrome UI框架的总体结构涉及通用代码的存放,...
Chrome_SPY 谷歌浏览器网页元素分析工具 Chrome_激活标签 (当前标签) 网页.跳转 (“www.baidu.com”) 程序__等待 (1000) 网页.取元素坐标 (“input”, “id=kw丨name=wd”, 0, 元素坐标) 提示 (“元素坐标 ...
10. **开发者工具**:Chrome DevTools也得到了更新,加入了新的调试和分析功能,如性能面板的改进,以及对 Progressive Web App (PWA) 更好的支持。 文件"59.0.3071.104_chrome_installer.exe"是Chrome 59的安装...
Axure RP Chrome 0.6.4 原型工具Chrome扩展插件,支持最新版本Chrome浏览器,安装方法如下(亲测可用): 1、打开谷歌浏览器,在浏览器中地址栏中输入chrome://extensions/,或者点击浏览器的右上角选择更多工具,...
ActiveX for Chrome是一款专为谷歌浏览器(Chrome)设计的ActiveX控件,允许用户在Chrome浏览器上运行需要ActiveX技术的网页应用。ActiveX是一种由微软开发的技术,主要用于Internet Explorer,它提供了创建和使用...
chrome96.0-99.0离线包,chrome96.0-99.0离线包chrome96.0-99.0离线包chrome96.0-99.0离线包chrome96.0-99.0离线包chrome96.0-99.0离线包chrome96.0-99.0离线包chrome96.0-99.0离线包chrome96.0-99.0离线包chrome...
7. **开发者工具**:Chrome的开发者工具是前端开发的重要辅助,V44可能引入了新的调试功能、性能分析工具,以及对移动设备模拟的改进。 8. **性能监控**:可能加入了更精确的性能监控工具,帮助开发者识别和解决...