如何在本机C ++ / nodejs插件中实现异步构造函数/工厂调用?

时间:2014-02-18 21:34:30

标签: c++ node.js v8 libuv

我对C ++和node / v8 Addon开发很新。

我正在尝试打包第三方C库。 一些初始化函数运行时间很长,我希望运行这些操作异步(借助libuv)。

鉴于我有以下代码:

#define BUILDING_NODE_EXTENSION
#include <node.h>
#include "myobject.h"

//header files of 3rd party lib to be wrapped
#include "3rdparty.h"

using namespace v8;

MyObject::MyObject(void* base) : baseobject_(base) {};
MyObject::~MyObject() {};

void MyObject::Init(Handle<Object> target) {
  // Prepare constructor template
  Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
  tpl->SetClassName(String::NewSymbol("MyObject"));
  tpl->InstanceTemplate()->SetInternalFieldCount(1);

  Persistent<Function> constructor = Persistent<Function>::New(tpl->GetFunction());
  target->Set(String::NewSymbol("MyObject"), constructor);
}

Handle<Value> MyObject::New(const Arguments& args) {
  HandleScope scope;
  if (args.IsConstructCall())
  {
    void* cStruct = NULL;

    //
    //VERY LONG TAKING OPERATION
    //Want to run this async with help of libuv
    createStructIn3rdPartyLib(&cStruct);

    //create actual Object and pass in cStruct which becomes private field.
    MyObject* obj = new MyObject(cStruct);
    obj->Wrap(args.This());
    return args.This();
  }

  return scope.Close(Undefined());
}

我希望在libuv-library的帮助下运行createStructIn3rdPartyLib(&cStruct);

以下是我提出的建议。不幸的是,它给了我一个分段错误,我不太确定它是否是正确的方法。 我已经查看了其他本地节点插件的来源,但没有找到任何解决我的问题的方法。 :(

欢迎任何提示。

#define BUILDING_NODE_EXTENSION
#include <node.h>
#include "myobject.h"

//header files of 3rd party lib to be wrapped
#include "3rdparty.h"

using namespace v8;

// libuv allows us to pass around a pointer to an arbitrary
// object when running asynchronous functions. We create a
// data structure to hold the data we need during and after
// the async work.
typedef struct AsyncData {
  Persistent<Function> callback; // callback function
  void *3rdpartydata
  Arguments *args;
} AsyncData;

MyObject::MyObject() {};
MyObject::~MyObject() {};

void MyObject::Init(Handle<Object> target) {
  // Prepare constructor template
  Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
  tpl->SetClassName(String::NewSymbol("MyObject"));
  tpl->InstanceTemplate()->SetInternalFieldCount(1);

  Persistent<Function> constructor = Persistent<Function>::New(tpl->GetFunction());
  target->Set(String::NewSymbol("MyObject"), constructor);
  target->Set(String::NewSymbol("createObject"), 
              FunctionTemplate::New(New)->GetFunction(CreateObjectAsync));

}

Handle<Value> MyObject::New(const Arguments& args) {
  HandleScope scope;
  if (args.IsConstructCall())
  {
    void* cStruct = NULL;

    //
    //VERY LONG TAKING OPERATION
    //Want to run this async with help of libuv
    createStructIn3rdPartyLib(&cStruct);

    //create actual Object and pass in cStruct which becomes private field.
    MyObject* obj = new MyObject(&cStruct);
    obj->Wrap(args.This());
    return args.This();
  }

  return scope.Close(Undefined());
}

Handle<Value> MyObject::CreateObjectAsync(const Arguments& args)
{
  HandleScope scope;
  // create an async work token
  uv_work_t *req = new uv_work_t;
  // assign our data structure that will be passed around
  AsyncData *asyncData = new AsyncData();
  req->data = asyncData;

  // expect a function as the 1st argument
  // we create a Persistent reference to it so
  // it won't be garbage-collected
  asyncData->callback = Persistent<Function>::New(
      Local<Function>::Cast(args[0]));

  *(asyncData->args) = args;

  // pass the work token to libuv to be run when a
  // worker-thread is available to
  uv_queue_work(
    uv_default_loop(),
    req,                          // work token
    AsyncWork,                    // work function
    (uv_after_work_cb)AsyncAfter  // function to run when complete
  );

  return scope.Close(Undefined());
}


// Function to execute inside the worker-thread.
// It is not safe to access V8, or V8 data structures
// here, so everything we need for input and output
// should go on our req->data object.
void MyObject::AsyncWork(uv_work_t *req) {
  // fetch our data structure
  AsyncData *asyncData = (AsyncData *)req->data;
  // run 3rd Party Function.
  createStructIn3rdPartyLib(&asyncData->3rdpartydata);
}

// Function to execute when the async work is complete
// this function will be run inside the main event loop
// so it is safe to use V8 again
void MyObject::AsyncAfter(uv_work_t *req) {
  HandleScope scope;

  // fetch our data structure
  AsyncData *asyncData = (AsyncData *)req->data;


  // create an arguments array for the callback
  MyObject *cpBase = new MyObject(asyncData->3rdpartydata);
  cpBase->Wrap((*asyncData->args).This());
  Handle<Value> argv[] = {Null(),(*asyncData->args).This()};

  // surround in a try/catch for safety
  TryCatch try_catch;
  // execute the callback function
  asyncData->callback->Call(Context::GetCurrent()->Global(), 2, argv);
  if (try_catch.HasCaught())
    node::FatalException(try_catch);

  // dispose the Persistent handle so the callback
  // function can be garbage-collected
  asyncData->callback.Dispose();
  // clean up any memory we allocated
  delete asyncData;
  delete req;
}

谢谢!!!

修改 我在阅读了更多像node-ogg bindings这样的例子后,我越来越多地想到我的方法是错误的。也许我应该在C / C ++-Side上保持更低的水平,并在javascript端实现对象功能。

0 个答案:

没有答案