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.

Note: JavaScript code cannot use the techniques described in this article. Chrome JavaScript should instead use workers.

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

词条统计

浏览:104 次

字数:4833

最后编辑:8年前

编辑次数:0 次

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文