Как вы можете вызвать обратный вызов эмиттера из отдельного потока C ++ в аддоне? - PullRequest
2 голосов
/ 16 апреля 2019

Для контекста я начал с этого вопроса. Мне нужно вызвать обратный вызов для эмиттера в другом потоке. Я сделал минимальный пример, но он вызывает ошибку на emit.Call({cb, result}); Мой первый инстинкт - проблема с временем жизни env или emit.

addon.cpp

#include <napi.h>
#include <iostream>
#include <thread>
#include <memory>
#include <functional>
#include <chrono>

std::shared_ptr<std::thread> thread;
bool running = true;

void generate(Napi::Env& env, Napi::Function& emit)
{
  while(running)
  {
    Napi::Array result = Napi::Array::New(env);

    for(int i = 0; i < 3; ++i)
    {
      result[i] = rand()%100;
    }

    auto cb = Napi::String::New(env, "onFeedData");

    emit.Call({cb, result});

    std::this_thread::sleep_for(std::chrono::seconds(1));
  }
}

Napi::Value Start(const Napi::CallbackInfo& info)
{
  Napi::Env env = info.Env();
  Napi::Function emit = info[0].As<Napi::Function>();

  auto cb = std::bind(generate, env, emit);
  thread = std::make_shared<std::thread>(cb);

  return Napi::String::New(env, "OK");
}

Napi::Value Stop(const Napi::CallbackInfo& info)
{
  Napi::Env env = info.Env();
  Napi::Function emit = info[0].As<Napi::Function>();

  running = false;
  thread->join();

  return Napi::String::New(env, "OK");
}

Napi::Object Init(Napi::Env env, Napi::Object exports)
{
  exports.Set(
      Napi::String::New(env, "Start"),
      Napi::Function::New(env, Start));

  exports.Set(Napi::String::New(env, "Stop"),
      Napi::Function::New(env, Stop));

  return exports;
}

NODE_API_MODULE(addon, Init)

index.js

'use strict'

const EventEmitter = require('events').EventEmitter;
const addon = require('./build/addon.node');

function Main() {
  const emitter = new EventEmitter();

  emitter.on('onFeedData', (evt) => {
    console.log(evt);
  })

  setTimeout(() => {
    addon.Stop( emitter.emit.bind(emitter) );
  }, 5000);

  addon.Start( emitter.emit.bind(emitter) );
}

Main();

1 Ответ

1 голос
/ 17 апреля 2019

Я не пробовал этого, но я знаю, что в node.js v10.6 введены асинхронные поточно-безопасные вызовы функций, он все еще находится в экспериментальном состоянии с уровнем стабильности 1. Использование также имеет определенные ограничения , вот фрагмент из документации по node.js.

Функции JavaScript обычно можно вызывать только из основного потока нативного дополнения.Если аддон создает дополнительные потоки, функции N-API, для которых требуются napi_env, napi_value или napi_ref, не должны вызываться из этих потоков.

Когда у аддона есть дополнительные потоки, и функции JavaScript должны вызываться на основе обработки, выполняемой этими потоками, эти потоки должны взаимодействовать с основным потоком аддона, чтобы основной поток мог вызывать функцию JavaScript от их имени.,API-интерфейсы для работы с потоками обеспечивают простой способ сделать это.

Вы можете получить полную документацию по этому вопросу. Асинхронные поточно-ориентированные вызовы функций

...