Node.js howto: make asynchronous callback from thread

来源:互联网 发布:网络通畅 但打不开网页 编辑:程序博客网 时间:2024/05/16 12:51

Since Node.js uses libuv to perform event loop in main thread, all asynchronous callbacks from out thread should fall into main thread. If we directly emit callback from our thread, system core dump occurs. The way making asynchronous callbacks is posting request(the uv_work_t* object) into Node.js main thread, carrying our data, letting the Node.js' main thread(the V8 engine thread) does the calling.

The following code represents how to do that by creating a node.js module which runs a different thread and fires the callback.

1. Makefile.

CC=g++addon.o: \  addon.cxx  $(CC) -o addon.o addon.cxx

2. binding.gyp

{  "targets": [    {      "cflags": ["-fpermissive", "-fexceptions", "-std=c++0x", "-fPIC"],      #"ldflags":["-L/usr/lib/", "-lboost_thread"],      "libraries":["/usr/lib/libboost_thread.so"],      "cflags_cc!":["-fno-rtti", "-fno-exceptions"],      "cflags_cc+":["-frtti", "-fexceptions"],      "target_name": "addon",      "sources": ["addon.cxx"]    }  ]}

3. addon.cxx

#include <v8.h>#include <node.h>#include <boost/date_time/posix_time/posix_time.hpp>#include <boost/thread/thread.hpp>#include <iostream>using namespace v8;Persistent<Function> theCallback;void nop(uv_work_t* req){  // Do nothing.}void uv_exit(uv_work_t* req, int status){  delete req;  HandleScope scope;  const unsigned argc = 1;  Local<Value> argv[argc] = {    Integer::New(-1)  };  theCallback->Call(Context::GetCurrent()->Global(), argc, argv);  theCallback.Dispose();}void uv_req(uv_work_t* req, int status){  int x = (int)(req->data);  delete req;  HandleScope scope;  const unsigned argc = 1;  Local<Value> argv[argc] = {    Local<Value>::New(Integer::New(x))  };  theCallback->Call(Context::GetCurrent()->Global(), argc, argv);}Handle<Value> RunCallback(const Arguments& args){  HandleScope scope;  theCallback = Persistent<Function>::New(Local<Function>::Cast(args[0]));  boost::thread thd([](){    uv_work_t* uv;    for(int i = 0; ; i++)    {      uv = new uv_work_t;      uv->data = i;      int r = uv_queue_work(uv_default_loop(), uv, nop, uv_req);      if (r != 0)      {        delete uv;      }    }    uv = new uv_work_t;    uv->data = 0;    int r = uv_queue_work(uv_default_loop(), uv, nop, uv_exit);    if (r != 0)    {      delete uv;    }    // Give up CPU    boost::this_thread::sleep(boost::posix_time::milliseconds(100));  });  return scope.Close(Undefined());}void Init(Handle<Object> exports, Handle<Object> module){  module->Set(String::NewSymbol("exports"),    FunctionTemplate::New(RunCallback)->GetFunction());}NODE_MODULE(addon, Init)

4. test.js

var x = require('./build/Debug/addon');x(function(arg){  console.log(arg);});

5. Configure, make and run.

$node-gyp configure && node-gyp build && node test.js

The console will relentless print numbers until ctrl-c has been pressed.


Good luck! :-)



0 0