logidelic logidelic - 6 months ago 185
Javascript Question

Callback NodeJS Javascript function from multithreaded C++ addon

I have a multithreaded C++ addon that does some background processing and I need to have it periodically callback to a Javascript function that I wrote in my NodeJS server.

I understand that this involves using uv_async_send(), since it needs to get executed in the main thread, but thus far I haven't been able to figure out how to do it.

Is there a simple example out there that I've missed?

Answer

Finally, this was not too difficult once I understood what the the uv_* functions do:

1) Expose a function in the addon to allow Node to set the Javascript cb that will be periodically called back to:

Callback* cbPeriodic; // keep cbPeriodic somewhere
NAN_METHOD(setPeriodicCb) {
    cbPeriodic = new Callback(info[0].As<Function>());
    //...
}

2) Init UV with an uv_async_t instance and a function that will be executed in the main thread by UV when our worker thread calls uv_async_send()

uv_async_t async; // keep this instance around for as long as we might need to do the periodic callback
uv_loop_t* loop = uv_default_loop();
uv_async_init(loop, &async, asyncmsg);

void asyncmsg(uv_async_t* handle) {
  // Called by UV in main thread after our worker thread calls uv_async_send()
  //    I.e. it's safe to callback to the CB we defined in node!
  Nan::HandleScope scope;
  v8::Isolate* isolate = v8::Isolate::GetCurrent();
  Local<Value> argv[] = { v8::String::NewFromUtf8(isolate, "Hello world") };
  cbPeriodic->Call(1, argv);
}

3) Call uv_async_send from a worker thread, passing our async instance above, whenever we need to do the periodic callback

uv_async_send(&async);

4) Finally, when we no longer need to execute the callback ever again, clean things up:

uv_close((uv_handle_t*) &async, NULL);
Comments