好的,我有一个 C++ 函数,需要从 JavaScript 调用,其中一个参数是 JavaScript 对象。 JavaScript 看起来像这样:
var message = {
fieldA: 42,
fieldB: "moo"
};
myObj.send(message, function (err) { console.log("Result: " + err); });
在 send() 例程中,我需要调用另一个可能会阻塞的 C 库中的 native 函数。该库中的所有函数都可能会阻塞,因此我一直在广泛使用 uv_queue_work 。
这个例程是我第一次遇到问题,这是因为 JavaScript 对象。 C++ 代码如下所示:
struct SendMessageRequest
{
Persistent<Object> message;
Persistent<Function> callback;
int result;
};
Handle<Value> MyObj::Send(const Arguments& args)
{
HandleScope scope;
// Parameter checking done but not included here
Local<Object> message = Local<Object>::Cast(args[0]);
Local<Function> callback = Local<Function>::Cast(args[1]);
// Send data to worker thread
SendMessageRequest* request = new SendMessageRequest;
request->message = Persistent<Object>::New(message);
request->callback = Persistent<Function>::New(callback);
uv_work_t* req = new uv_work_t();
req->data = request;
uv_queue_work(uv_default_loop(), req, SendMessageWorker, SendMessageWorkerComplete);
return scope.Close(Undefined());
}
这一切都很好,当我尝试访问 SendMessageWorker 函数中的 request->message 时,问题就出现了。
void SendMessageWorker(uv_work_t* req)
{
SendMessageRequest* request = (SendMessageRequest*)req->data;
Local<Array> names = request->message->GetPropertyNames();
// CRASH
似乎从 request->message 调用方法会导致在一个非常小的地址上发生访问冲突(可能是 V8/节点中某处的 NULL 指针引用)。所以直接使用request->message肯定是错误的。我知道要访问回调函数我需要这样做:
request->callback->Call(Context::GetCurrent()->Global(), 1, argv);
我是否需要使用 Context::GetCurrent()->Global() 才能访问由持久模板包装的 Object 类的方法?如果是这样我该怎么做?
最佳答案
SendMessageWorker
中的代码不在 JavaScript 上执行 - uv_queue_work
所做的是在单独的线程中执行 SendMessageWorker
,因此它可以让 Node.js 代码也运行,当它准备好时,SendMessageWorkerComplete
将在 JavaScript 线程上执行。
所以你不能在 SendMessageWorker 中使用 JavaScript 变量 - 如果你确实需要,你必须将它们转换为例如调用 uv_queue_work
之前的 C++ 字符串。
关于V8:将对象从 JavaScript 传递到 uv_work 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11110369/