Двойной вызов некоторой функции обратного вызова приводит к ошибке сегментации: 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 в любой момент времени.