Двойной вызов некоторой функции обратного вызова приводит к ошибке сегментации: Nan

Я пишу аддон C++, используя ссылку nbind - GitHub для большинства вещей и ссылку Nan - GitHub для вызова обратных вызовов асинхронным. Когда я вызываю обратный вызов только один раз, он отлично работает. Но когда я вызываю обратный вызов дважды, это дает Segmentation fault (core dumped), Не удалось найти ошибку при использовании gdb, Вот коды JS и C++ (компиляция с использованием node-gyp configure build):

//main.js code
var nbind = require('nbind');
var lib = nbind.init().lib;

lib.HeaderExample.callJS(function(a) {
console.log("result" + a);
});

lib.HeaderExample.startThread();
lib.HeaderExample.startThread(); 

C++ аддон код

//c++ code
class CallbackRunner : public Nan::AsyncWorker {
public:
    CallbackRunner(Nan::Callback *callback)
            : AsyncWorker(callback) {}
    void Execute () {}
    void HandleOKCallback () {
        std::cout << "running HandleOKCallback in thread " << std::this_thread::get_id() << std::endl;
        Nan::HandleScope scope;
        v8::Local<v8::Value> argv[] = {
                Nan::New<v8::Number>(10)
        };
        callback->Call(1, argv);
    }
};

class HeaderExample {
public:
    static void callJS(nbind::cbFunction &callback) {
        std::cout << "running callJS in thread " << std::this_thread::get_id() << std::endl;
        m_onInitialisationStarted = new nbind::cbFunction(callback);
        Nan::Callback *callbackNan = new Nan::Callback(m_onInitialisationStarted->getJsFunction());
        runner = new CallbackRunner(callbackNan);
    }
    static void startThread() {
        std::cout << "it is here";
        std::thread threadS(some);
        threadS.join();
    }
    static void some() {
        std::cout << "running some in thread: " << std::this_thread::get_id() << std::endl;
        if(runner){
        AsyncQueueWorker(runner);
        }
    }
    inline static nbind::cbFunction *m_onInitialisationStarted = 0;
    inline static CallbackRunner *runner;
};

2 ответа

Решение

Ваш класс использует AsyncQueueWorker призвать CallbackRunner, но AsyncQueueWorker звонки AsyncExecuteComplete после обратного вызова, который в свою очередь вызывает worker->Destroy(), Увидеть AsyncQueueWorker код из nan.h:

inline void AsyncExecute (uv_work_t* req) {
  AsyncWorker *worker = static_cast<AsyncWorker*>(req->data);
  worker->Execute();
}

inline void AsyncExecuteComplete (uv_work_t* req) {
  AsyncWorker* worker = static_cast<AsyncWorker*>(req->data);
  worker->WorkComplete();
  worker->Destroy();
}

inline void AsyncQueueWorker (AsyncWorker* worker) {
  uv_queue_work(
      uv_default_loop()
    , &worker->request
    , AsyncExecute
    , reinterpret_cast<uv_after_work_cb>(AsyncExecuteComplete)
  );
}

worker->Destroy() удалит CallbackRunner класс, наряду с Nan::Callback что ты скормил своему конструктору. По этой причине вы получаете ошибку сегментации при попытке вызвать этот обратный вызов во второй раз.

Вы могли бы лучше основывать свой класс на Nan::AsyncProgressQueueWorker вместо Nan::AsyncWorker, AsyncProgressQueueWorker наследуется AsyncWorker и это позволяет планировать работу из основного потока так же, как AsyncWorker делает, но это дает вам ExecutionProgress класс, который позволяет вам использовать любой поток для обратного вызова основного потока любое количество раз, пока выполняется исходное запланированное задание.

Nan::AsyncProgressQueueWorker был добавлен в NAN в версии 2.8.0

Вы не можете иметь два потока, вызывающих один и тот же экземпляр V8 одновременно. Вам понадобится тщательная блокировка, чтобы убедиться, что только один поток взаимодействует с V8 в любой момент времени.

Другие вопросы по тегам