node.js关于c++addon生命周期的疑问
发布于 9 年前 作者 zhi721561 4215 次浏览 最后一次编辑是 8 年前 来自 问答

大家好,我在写c++addon的时候有一个疑问,比如我在PlusOne这个方法里面有一个耗时的线程处理,每隔100ms触发一次js的回调函数,为什么我运行1分多钟之后,gc把MyObject对象给析构掉了?导致后面的程序出错了。请问这是什么原因导致的?如果我想实现这样的功能有没有其他的思路可以实现呢?附代码如下: // myobject.cc #include “myobject.h” #include <Windows.h> #include <vector> #include <string> #include <assert.h> using namespace std; using namespace v8;

Persistent<Function> MyObject::constructor; v8::Persistentv8::Function OnPlayRecordEnd; uv_async_t on_play_record_end_callback_;

typedef struct stSndUtilData { // 请求主体 //uv_async_t request_; // 回调处理函数 v8::Persistentv8::Function* callback_; // 回调数据队列 double pData_; }ST_SNDUTIL_DATA, *PT_ST_SNDUTIL_DATA;

void UV_Async_Handler(uv_async_t handle) { Isolate isolate = Isolate::GetCurrent(); HandleScope handle_scope(isolate); PT_ST_SNDUTIL_DATA data = (PT_ST_SNDUTIL_DATA)handle->data; Local<Value> argv[1] = { Number::New(isolate, data->pData_) }; Local<Function>::New(isolate, *(data->callback_))->Call(isolate->GetCurrentContext()->Global(), 1, argv); delete data; }

MyObject::MyObject(double value) : value_(value) { uv_async_init(uv_default_loop(), &on_play_record_end_callback_, UV_Async_Handler); }

MyObject::~MyObject() { printf(“nihao”); }

void MyObject::Init(Handle<Object> exports) { Isolate* isolate = Isolate::GetCurrent();

// Prepare constructor template
Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New);
tpl->SetClassName(String::NewFromUtf8(isolate, "MyObject"));
tpl->InstanceTemplate()->SetInternalFieldCount(1);

// Prototype
NODE_SET_PROTOTYPE_METHOD(tpl, "plusOne", PlusOne);

constructor.Reset(isolate, tpl->GetFunction());
exports->Set(String::NewFromUtf8(isolate, "MyObject"),
	tpl->GetFunction());

}

void MyObject::New(const FunctionCallbackInfo<Value>& args) { Isolate* isolate = Isolate::GetCurrent(); HandleScope scope(isolate);

if (args.IsConstructCall()) {
	// Invoked as constructor: `new MyObject(...)`
	double value = args[0]->IsUndefined() ? 0 : args[0]->NumberValue();
	MyObject* obj = new MyObject(value);
	obj->Wrap(args.This());
	args.GetReturnValue().Set(args.This());
}
else {
	// Invoked as plain function `MyObject(...)`, turn into construct call.
	const int argc = 1;
	Local<Value> argv[argc] = { args[0] };
	Local<Function> cons = Local<Function>::New(isolate, constructor);
	args.GetReturnValue().Set(cons->NewInstance(argc, argv));
}

}

void OnDataStreamPublish(MyObject* p) { while (true) { PT_ST_SNDUTIL_DATA data = new ST_SNDUTIL_DATA(); assert(p->value_ == 11); data->pData_ = p->value_; data->callback_ = &OnPlayRecordEnd; on_play_record_end_callback_.data = (void*)data; uv_async_send(&on_play_record_end_callback_); Sleep(100); } }

void MyObject::PlusOne(const FunctionCallbackInfo<Value>& args) { Isolate* isolate = Isolate::GetCurrent(); HandleScope scope(isolate);

MyObject* obj = ObjectWrap::Unwrap<MyObject>(args.Holder());
obj->value_ += 1;
OnPlayRecordEnd.Reset(isolate, args[0].As<Function>());

HANDLE m_pThreadHandle = CreateThread(
	NULL,															// SD  
	0,																// initial stack size  
	(LPTHREAD_START_ROUTINE)OnDataStreamPublish,					// thread function  
	obj,															// thread argument  
	0,																// creation option  
	NULL															// thread identifier  
	);

args.GetReturnValue().Set(Number::New(isolate, obj->value_));

}

// myobject.h #ifndef MYOBJECT_H #define MYOBJECT_H

#include <node.h> #include <node_object_wrap.h> #include <uv/uv.h>

class MyObject : public node::ObjectWrap { public: static void Init(v8::Handlev8::Object exports); double value_;

private: explicit MyObject(double value = 0); ~MyObject();

static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
static void PlusOne(const v8::FunctionCallbackInfo<v8::Value>& args);
static v8::Persistent<v8::Function> constructor;

};

#endif

// addon.cc #include <node.h> #include “myobject.h”

using namespace v8;

void InitAll(Handle<Object> exports) { MyObject::Init(exports); }

NODE_MODULE(addon, InitAll)

// test.js var addon = require(’./MyObject’); var obj = new addon.MyObject(10); var i = 0; obj.plusOne(function (result) { i += 1; console.log(i + “:” + result);});

3 回复

没看懂, 异步不正常? 会不会是UV_Async_Handler 这个函数的问题?

@wewea 异步是正常的,初步定为应该是处在UV_Async_Handler这个方法里面,现象就是大概执行了6-700多次异步回调之后,MyObject这个对象就被析构了,不知道是什么原因导致的。如果把Local<Function>::New(isolate, *(data->callback_))->Call(isolate->GetCurrentContext()->Global(), 1, argv);这句话注释了就不会出现了。现在就搞不明白是什么原因导致的,能麻烦帮我稍微看看,给个方向也行!谢谢了

现在发现把test.js回调里面的console.log(i + “:” + result);注释了就不出问题了,加上就不行,请问这是为什么呢?

回到顶部