【问题标题】:Invoking some callback function twice leads to Segmentation fault: Nan调用某些回调函数两次导致分段错误:Nan
【发布时间】:2018-01-17 06:13:23
【问题描述】:

我正在编写 C++ 插件,使用 nbind - GitHub link 处理大多数事情,Nan - GitHub link 用于异步调用回调。当我只调用一次回调时,它可以完美运行。但是当我调用回调两次时,它会给出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;
};

【问题讨论】:

    标签: c++ node.js v8 libuv node.js-nan


    【解决方案1】:

    您不能让两个线程同时调用同一个 V8 实例。您需要小心锁定以确保在任何时间点只有一个线程与 V8 交互。

    【讨论】:

    • 嗨!我应该添加储物柜吗?
    • 是的,储物柜是实现这一目标的一种方式。 (另一个问题是拥有多个线程是否对您的用例有帮助;或者让所有这些线程在 V8 中执行自己的回调是否是最优雅或高性能的解决方案。由于您没有提供更多详细信息,因此我无法提供任何建议.)
    • 谢谢你的建议:) 这个例子只是模拟我的真实程序所做的。它是 (in c++) 在执行期间在其自己的线程中调用回调,应该在 JavaScript 中调用。需要哪些细节来澄清?我很乐意分享它;)
    • 嗯,根据您的操作,您可能根本不需要任何线程。或者,将程序的 C++ 端结构化,这样您就有一个与 V8 交互并管理工作线程池的“主”线程,这可能是最简单的。或者,当然你可以使用储物柜,这没有什么问题。
    • 是的,会很好。很好的主意。有什么例子吗?很高兴看到一些例子。
    【解决方案2】:

    您的类使用AsyncQueueWorker 调用CallbackRunner,但AsyncQueueWorker 在回调完成后调用AsyncExecuteComplete,而后者又调用worker-&gt;Destroy()。请参阅nan.h 中的AsyncQueueWorker 代码:

    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-&gt;Destroy() 将删除 CallbackRunner 类,以及您提供给其构造函数的 Nan::Callback。这就是您在尝试第二次调用此回调时遇到分段错误的原因。

    您最好将课程基于Nan::AsyncProgressQueueWorker 而不是Nan::AsyncWorkerAsyncProgressQueueWorker 继承 AsyncWorker,它允许您像 AsyncWorker 一样从主线程安排工作,但它为您提供了一个 ExecutionProgress 类,允许您使用任何线程回调到主线程中原始计划作业运行时的次数。

    Nan::AsyncProgressQueueWorker 已添加到版本 2.8.0

    中的 NAN

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-08-02
      • 1970-01-01
      • 2020-09-26
      • 1970-01-01
      • 2020-08-04
      • 2019-11-21
      • 2014-07-25
      • 2015-01-18
      相关资源
      最近更新 更多