Node プラグインを作成していますが、C++ ワーカー スレッドから V8 関数オブジェクトを呼び出そうとすると問題が発生します。
私のプラグインは基本的に C++ std::thread を開始し、WaitForSingleOject() を使用して待機ループに入ります。これは、共有メモリのビットに書き込む別の C++ アプリ (X-Plane プラグイン) によってトリガーされます。Windows共有イベントが通知されたときにNodeプラグインを起動させ、ノードアプリから登録したJavaScript関数を呼び出そうとしています。これにより、X-Planeで発生したデータがNodeに戻されますそしてウェブの世界。
JavaScript 関数を登録して C++ から呼び出す方法をなんとか見つけましたが、メインの V8 スレッドでのみです。std::thread から関数を呼び出す方法が見つからないようです。
さまざまなアプローチ、Locker オブジェクト (変数の成功)、Persistent 関数 (機能しませんでした)、メインの分離オブジェクトの保存、分離の開始/終了などを試しましたが、コードが最終的に関数オブジェクトに到達した場合は有効ではありません。
さまざまなロッカーおよびロック解除オブジェクトを作成するかどうかに応じて、クラッシュからフリーズまで、さまざまな結果が得られます。
私は 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);
}