Making cross-thread calls using runnables 编辑
In the Mozilla platform, most activities such as layout, DOM operations, content JavaScript, and chrome JavaScript run on the main thread. However, it may be useful for C++ code in the Mozilla platform to run tasks on another thread. Typically, thread activities are triggered and managed using an XPCOM event-passing framework that uses the nsIRunnable
interface. Each runnable represents a task which can then be dispatched to another thread for execution.
In general, threading and message passing should be asynchronous. For example, let's say we have a function, CalculatePi(int digits)
, which will calculate π to an arbitrary number of digits:
void CalculatePi(int digits, nsCString& result); // This is synchronous
This can take a while, so we don't want to run this on the main thread. Instead, we want to run it on a new thread and be notified when the result is available. So we declare an asynchronous version of the same function:
typedef void (*PiCallback)(const nsCString& result); // Callback function
void CalculatePiAsynchronously(int digits, PiCallback callback);
Creating a runnable
nsRunnable
is a helper class: it already implements threadsafe refcounting, so all you need to do is override the Run()
function. In our example, we actually need two runnables: one dispatched to the worker thread, and one to hand us back the result.
#include "nsThreadUtils.h"
class PiResultTask : public nsRunnable
{
public:
PiResultTask(PiCallback callback, const nsACString& result)
: mCallback(callback)
, mResult(result)
, mWorkerThread(do_GetCurrentThread())
{
MOZ_ASSERT(!NS_IsMainThread()); // This should be running on the worker thread
}
NS_IMETHOD Run() {
MOZ_ASSERT(NS_IsMainThread()); // This method is supposed to run on the main thread!
mCallback(mResult);
// If we don't destroy the thread when we're done with it, it will hang around forever... bad!
// But thread->Shutdown must be called from the main thread, not from the thread itself.
mWorkerThread->Shutdown();
}
private:
PiCallback mCallback;
nsCString mResult;
nsCOMPtr<nsIThread> mWorkerThread;
};
class PiCalculateTask : public nsRunnable
{
public:
PiCalculateTask(PiCallback callback, int digits)
: mCallback(callback)
, mDigits(digits)
{ }
NS_IMETHOD Run() {
nsCString result;
CalculatePi(mDigits, result);
nsCOMPtr<nsIRunnable> resultrunnable = new PiResultTask(mCallback, result);
NS_DispatchToMainThread(resultrunnable);
}
private:
PiCallback mCallback;
int mDigits;
};
Putting it all together
To start a new thread, create it using the Thread Manager:
#include "nsXPCOMCIDInternal.h"
void CalculatePiAsynchronously(int digits, PiCallback callback)
{
// To create a new thread, get the thread manager
nsCOMPtr<nsIThreadManager> tm = do_GetService(NS_THREADMANAGER_CONTRACTID);
nsCOMPtr<nsIThread> mythread;
nsresult rv = tm->NewThread(0, 0, getter_AddRefs(mythread));
if (NS_FAILED(rv)) {
// In case of failure, call back immediately with an empty string which indicates failure
callback(EmptyCString());
return;
}
nsCOMPtr<nsIRunnable> r = new PiCalculateTask(callback, digits);
mythread->Dispatch(r, nsIEventTarget::DISPATCH_NORMAL);
// The result callback will shut down the worker thread, we can let it go here...
}
See also
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论