Блокировка звонков в аддоне Node.js - PullRequest
0 голосов
/ 13 марта 2019

Я разрабатываю приложение Node.js, которое включает в себя Windows DLL.DLL управляет научным оборудованием, для контекста.

Мой интерфейс от Node к DLL работает хорошо, однако DLL имеет некоторые недетерминированные вызовы, которые зависят от топологии сети и радиочастотных сигналов в комнате.Эти вызовы могут занимать от 10 секунд до 10 минут.

Я бы хотел отключить эти вызовы от цикла обработки событий Node и даже избегать AsyncWorkers.Я хотел бы поместить их в свои собственные потоки C ++.Я беспокоюсь, что не знаю достаточно Node / V8, чтобы правильно подойти к проблеме, хотя я уже дважды пытался это сделать.

Ниже приведена моя попытка создать поток для вызова обратного вызова js, хотя яЯ не уверен, что это хороший подход.Мне нужен результат вызова, и у меня до сих пор есть «демон» в приложении моего узла, который регулярно проверяет результаты поиска выполненных задач.

mTp во фрагменте ниже:реализация пула потоков, которую я написал.Runtask принимает лямбда-код C ++ в качестве параметра для добавления в мою очередь рабочих потоков.mThreadStatus - это карта из моего дескриптора потока, который является строкой, в перечисление thread_status_t.mThreadResults - это еще одна карта из дескриптора потока в v8 :: Value, которая возвращается обратным вызовом.

void
MyObj::SpawnThread(functionInput info) {
    MyObj* obj = ObjectWrap::Unwrap<MyObj>(info.Holder());      
    obj->mTp.RunTask([&]() {
        v8::Isolate::CreateParams cp;
        v8::Isolate* tpIsolate = v8::Isolate::New(cp);
        v8::Locker locker(tpIsolate);
        v8::Isolate::Scope isolateScope(tpIsolate);

        Nan::HandleScope scope;

        auto global = obj->mContext.Get(tpIsolate)->Global();

        auto handle = std::string(*v8::String::Utf8Value(info[0]->ToString()));

        {
            std::unique_lock<std::shared_mutex> lock(obj->mThreadStatusMutex);
            obj->mThreadStatus[handle] = thread_status_t::running;
        }

        v8::Handle<v8::Function> f = v8::Handle<v8::Function>::Cast(info[1]);
        v8::TryCatch trycatch(tpIsolate);
        v8::Handle<v8::Value> result = f->Call(global, 0, nullptr);
        if (result.IsEmpty()) {
            v8::Local<v8::Value> exception = trycatch.Exception();
            std::unique_lock<std::shared_mutex> lock(obj->mThreadStatusMutex);
            obj->mThreadStatus[handle] = thread_status_t::error;
            return;
        }

        {
            std::unique_lock<std::shared_mutex> resultLock(obj->mThreadResultsMutex);
            obj->mThreadResults[handle] = result;
        }

        std::unique_lock<std::shared_mutex> lock(obj->mThreadStatusMutex);
        obj->mThreadStatus[handle] = completed;

        tpIsolate->Dispose();
    });

Я предполагаю, что мои js выглядят так, чтобы порождать поток:

var ctx = this
this.myObj.spawnThread('startMeasurements', () => {
    return ctx.myObj.startMeasurements()
})

И вот так, чтобы получить результат, в моем 'демоне':

var status = this.myObj.getThreadStatus('startMeasurements')
if ( status === 'complete') {
    // Publish returned information to front-end
}
else if (status === 'error') {
    // Handle error
}

Кто-нибудь раньше решал эту проблему?Это похоже на достойный подход?Помощь с v8 очень ценится.Спасибо!

1 Ответ

1 голос
/ 13 марта 2019

Ранее я не решал подобную проблему, но в общем случае я бы сказал:

  • пусть код JavaScript не обращает внимания на потоки
  • выставить функцию getMeasurements(callback) в JavaScript, реализованную в C ++
  • когда функция вызывается, она сама получает поток (либо вновь созданный, либо из пула) и инструктирует его выполнить блокирующий внешний вызов; когда этот вызов завершен, поток сообщает свой результат основному потоку, который вызывает callback с ним.
  • таким образом, все взаимодействие с кодом JavaScript (т.е. все взаимодействие с V8) происходит в основном потоке, и вы используете только фоновые потоки для блокирующих вызовов.

Надеюсь, это поможет!

...