Функция обратного вызова NodeJS Javascript из многопоточного аддона C++
У меня есть многопоточный аддон C++, который выполняет некоторую фоновую обработку, и мне необходимо периодически вызывать его для функции Javascript, которую я написал на своем сервере NodeJS.
Я понимаю, что это включает в себя использование uv_async_send(), так как он должен выполняться в главном потоке, но до сих пор я не смог понять, как это сделать.
Есть ли простой пример, который я пропустил?
1 ответ
Наконец, это не было слишком сложно, когда я понял, что делают функции uv_*:
1) Предоставьте функцию в аддоне, чтобы позволить узлу установить Cav Javascript, который будет периодически вызываться обратно:
Callback* cbPeriodic; // keep cbPeriodic somewhere
NAN_METHOD(setPeriodicCb) {
cbPeriodic = new Callback(info[0].As<Function>());
//...
}
2) Init UV с uv_async_t
экземпляр и функция, которая будет выполняться в главном потоке UV, когда наш рабочий поток вызывает 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) Позвонить uv_async_send
из рабочего потока, передавая наш асинхронный экземпляр выше, всякий раз, когда нам нужно сделать периодический обратный вызов
uv_async_send(&async);
4) Наконец, когда нам больше не нужно выполнять обратный вызов, очистите вещи:
uv_close((uv_handle_t*) &async, NULL);
Приложение:
С тех пор как я написал этот ответ, я столкнулся с другими проблемами и, наконец, усвоил некоторые уроки о libuv. Для полноты вы должны понимать:
Помимо
uv_async_send
все функции libuv могут вызываться только из потока основного цикла! (Я видел, что упоминалось, что другие не были потокобезопасными, но это слишком слабое утверждение.) Даже, например,uv_async_init
а такжеuv_close
должен быть вызван из основного потока цикла.Если твой
uv_async_t
Экземпляр распределяется динамически, обратите внимание, что вы не можете освобождать память до тех пор, пока uv_close не сделает обратный вызов, чтобы вы знали, что это безопасно.
То есть:
auto async = new uv_async_t();
...
uv_close((uv_handle_t*)async, [](uv_handle_t* handle) {
delete handle;
});