工作线程的支持
为了从多个 Node.js 环境(例如主线程和工作线程)加载,插件需要:
- 成为 Node-API 插件,或
- 如上所述使用
NODE_MODULE_INIT()
声明为上下文感知
为了支持 Worker
线程,插件需要清理它们可能在此类线程存在时分配的任何资源。
这可以通过使用 AddEnvironmentCleanupHook()
函数来实现:
void AddEnvironmentCleanupHook(v8::Isolate* isolate,
void (*fun)(void* arg),
void* arg);
此函数添加了一个钩子,该钩子将在给定的 Node.js 实例关闭之前运行。
如有必要,可以在使用具有相同签名的 RemoveEnvironmentCleanupHook()
运行这些钩子之前将其删除。
回调按后进先出的顺序运行。
如有必要,还有一对额外的 AddEnvironmentCleanupHook()
和 RemoveEnvironmentCleanupHook()
重载,其中清理钩子采用回调函数。
这可用于关闭异步资源,例如插件注册的任何 libuv 句柄。
以下 addon.cc
使用 AddEnvironmentCleanupHook
:
// addon.cc
#include <node.h>
#include <assert.h>
#include <stdlib.h>
using node::AddEnvironmentCleanupHook;
using v8::HandleScope;
using v8::Isolate;
using v8::Local;
using v8::Object;
// 注意:在实际应用程序中,不要依赖静态/全局数据。
static char cookie[] = "yum yum";
static int cleanup_cb1_called = 0;
static int cleanup_cb2_called = 0;
static void cleanup_cb1(void* arg) {
Isolate* isolate = static_cast<Isolate*>(arg);
HandleScope scope(isolate);
Local<Object> obj = Object::New(isolate);
assert(!obj.IsEmpty()); // 断言 VM 仍旧存活
assert(obj->IsObject());
cleanup_cb1_called++;
}
static void cleanup_cb2(void* arg) {
assert(arg == static_cast<void*>(cookie));
cleanup_cb2_called++;
}
static void sanity_check(void*) {
assert(cleanup_cb1_called == 1);
assert(cleanup_cb2_called == 1);
}
// 将此插件初始化为上下文感知。
NODE_MODULE_INIT(/* exports, module, context */) {
Isolate* isolate = context->GetIsolate();
AddEnvironmentCleanupHook(isolate, sanity_check, nullptr);
AddEnvironmentCleanupHook(isolate, cleanup_cb2, cookie);
AddEnvironmentCleanupHook(isolate, cleanup_cb1, isolate);
}
通过运行在 JavaScript 中进行测试:
// test.js
require('./build/Release/addon');
In order to be loaded from multiple Node.js environments, such as a main thread and a Worker thread, an add-on needs to either:
- Be an Node-API addon, or
- Be declared as context-aware using
NODE_MODULE_INIT()
as described above
In order to support Worker
threads, addons need to clean up any resources
they may have allocated when such a thread exists. This can be achieved through
the usage of the AddEnvironmentCleanupHook()
function:
void AddEnvironmentCleanupHook(v8::Isolate* isolate,
void (*fun)(void* arg),
void* arg);
This function adds a hook that will run before a given Node.js instance shuts
down. If necessary, such hooks can be removed before they are run using
RemoveEnvironmentCleanupHook()
, which has the same signature. Callbacks are
run in last-in first-out order.
If necessary, there is an additional pair of AddEnvironmentCleanupHook()
and RemoveEnvironmentCleanupHook()
overloads, where the cleanup hook takes a
callback function. This can be used for shutting down asynchronous resources,
such as any libuv handles registered by the addon.
The following addon.cc
uses AddEnvironmentCleanupHook
:
// addon.cc
#include <node.h>
#include <assert.h>
#include <stdlib.h>
using node::AddEnvironmentCleanupHook;
using v8::HandleScope;
using v8::Isolate;
using v8::Local;
using v8::Object;
// Note: In a real-world application, do not rely on static/global data.
static char cookie[] = "yum yum";
static int cleanup_cb1_called = 0;
static int cleanup_cb2_called = 0;
static void cleanup_cb1(void* arg) {
Isolate* isolate = static_cast<Isolate*>(arg);
HandleScope scope(isolate);
Local<Object> obj = Object::New(isolate);
assert(!obj.IsEmpty()); // assert VM is still alive
assert(obj->IsObject());
cleanup_cb1_called++;
}
static void cleanup_cb2(void* arg) {
assert(arg == static_cast<void*>(cookie));
cleanup_cb2_called++;
}
static void sanity_check(void*) {
assert(cleanup_cb1_called == 1);
assert(cleanup_cb2_called == 1);
}
// Initialize this addon to be context-aware.
NODE_MODULE_INIT(/* exports, module, context */) {
Isolate* isolate = context->GetIsolate();
AddEnvironmentCleanupHook(isolate, sanity_check, nullptr);
AddEnvironmentCleanupHook(isolate, cleanup_cb2, cookie);
AddEnvironmentCleanupHook(isolate, cleanup_cb1, isolate);
}
Test in JavaScript by running:
// test.js
require('./build/Release/addon');