我正在编写一个 Node 插件,但在尝试从 C++ 工作线程调用 V8 函数对象时遇到问题。
我的插件基本上启动了一个 C++ std::thread 并使用 WaitForSingleOject() 进入一个等待循环,这是由另一个 C++ 应用程序(一个 X-Plane 插件)写入一点共享内存触发的。我试图让我的 Node 插件在 Windows 共享事件发出信号时唤醒,然后调用我从节点应用程序注册的 JavaScript 函数,该函数又会将源自 X-Plane 的数据传递回 Node和网络世界。
我已经设法弄清楚如何注册一个 JavaScript 函数并从 C++ 调用它,但仅限于 V8 主线程。我似乎找不到从 std::thread 调用函数的方法。
我尝试了各种方法,Locker 对象(变量成功),持久函数(不起作用),保存主隔离对象,进入/退出隔离,但是如果/当代码最终到达函数对象时它是无效的。
我得到不同的结果,从崩溃到冻结,这取决于我是否创建了各种储物柜和解锁器对象。
我对 V8 完全陌生,所以我不确定我做对了什么。有问题的代码如下:
如果有人可以提供帮助,我将永远感激不尽!
float* mem = 0;
HANDLE event = NULL;
Isolate* thisIsolate;
void readSharedMemory()
{
//Isolate* isolate = Isolate::GetCurrent();
//HandleScope scope(isolate);
thisIsolate->Enter();
v8::Locker locker(thisIsolate);
v8::Isolate::Scope isolateScope(thisIsolate);
//HandleScope scope(thisIsolate);
//v8::Local<Value> myVal = v8::String::NewFromUtf8(isolate, "Plugin world");
v8::Local<Value> myVal = v8::Number::New(thisIsolate, *mem);
// If it get's this far 'myFunction' is not valid
bool isFun = myFunction->IsFunction();
isFun = callbackFunction->IsFunction();
v8::Context *thisContext = *(thisIsolate->GetCurrentContext());
myFunction->Call(thisContext->Global(), 1, &(Handle<Value>(myVal)));
}
void registerCallback(const FunctionCallbackInfo<Value>& args)
{
Isolate* isolate = Isolate::GetCurrent();
v8::Locker locker(isolate);
HandleScope scope(isolate);
/** Standard parameter checking code removed **/
// Various attempts at saving a function object
v8::Local<v8::Value> func = args[0];
bool isFun = func->IsFunction();
Handle<Object> callbackObject = args[0]->ToObject();
callbackFunction = Handle<Function>::Cast(callbackObject);
isFun = callbackFunction->IsFunction();
// save the function call object - This appears to work
myFunction = v8::Function::Cast(*callbackObject);
isFun = myFunction->IsFunction();
// Test the function - this works *without* the Unlocker object below
v8::Local<Value> myVal = v8::String::NewFromUtf8(isolate, "Plugin world");
myFunction->Call(isolate->GetCurrentContext()->Global(), 1, &(Handle<Value>(myVal)));
}
void threadFunc()
{
thisIsolate->Exit();
// If I include this unlocker, the function call test above fails.
// If I don't include it, the app hangs trying to create the locker in 'readSharedMemory()'
//v8::Unlocker unlocker(thisIsolate);
event = OpenEventW(EVENT_ALL_ACCESS, FALSE, L"Global\\myEventObject");
DWORD err = GetLastError();
//thisIsolate = v8::Isolate::New();
std::cout << "Hello from thread" << std::endl;
bool runThread = true;
while (runThread)
{
DWORD dwWaitResult;
DWORD waitTime = 60000;
dwWaitResult = WaitForSingleObject(event, waitTime);
err = GetLastError();
if (dwWaitResult == WAIT_TIMEOUT)
runThread = false;
// event has been signaled - continue
readSharedMemory();
}
}
void init(Handle<Object> exports)
{
/** NODE INITILISATION STUFF REMOVED **/
// save the isolate - Is this a safe thing to do?
thisIsolate = Isolate::GetCurrent();
//Launch a thread
eventThread = std::thread(threadFunc);
}