问题
I am writing C++ addon using nbind - GitHub link for most thing and Nan - GitHub link for calling callbacks asynchronous. When I invoke callback only once, it works perfect. But When I invoke callback twice it gives Segmentation fault (core dumped)
. Couldn't find error using gdb
. Here is JS and C++ codes(compiling using 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++ addon's code
//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;
};
回答1:
Your class uses AsyncQueueWorker
to invoke the CallbackRunner
, but AsyncQueueWorker
calls AsyncExecuteComplete
after the callback is done, which in turn calls worker->Destroy()
. See the AsyncQueueWorker
code from 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()
will delete the CallbackRunner
class, along with the Nan::Callback
that you fed to its constructor. That is the reason why you get a segmentation fault when attempting to call this callback a second time.
You might be better off basing your class on Nan::AsyncProgressQueueWorker
instead of Nan::AsyncWorker
. AsyncProgressQueueWorker
inherits AsyncWorker
and it allows you to schedule work from the main thread just as AsyncWorker
does, but it provides you with an ExecutionProgress
class that allows you to use any thread to call back into the main thread any number of times while the original scheduled job is running.
Nan::AsyncProgressQueueWorker
was added to NAN in version 2.8.0
回答2:
You can't have two threads calling into the same V8 instance concurrently. You'll need careful locking to make sure that only one thread interacts with V8 at any point in time.
来源:https://stackoverflow.com/questions/45589254/invoking-some-callback-function-twice-leads-to-segmentation-fault-nan