您的位置:首页 > Web前端 > Node.js

node-haystack Episode 3: Callback model in C++

2016-09-09 17:27 253 查看

Prerequisite

This article assumes readers have the following knowledge:

C++14

Multi-Thread

Boost

JavaScript

node.js and add-on

Linux

Callback Mechanism

We have two kinds of callback, one for C++ and another for JavaScript.

In libuv, the callback function will take over the control when job is done. A C style callback is a plaint function. A C++ wrapper of libuv must handle these callbacks and transform them into C++ style. In JavaScript, because of its closure mechanism, life becomes much easier than C++.

C++ Callback

Thanks for C++14, it makes callback a piece of case. We can play the callback function around anywhere. Here is a simple example:

// For C++14
#include <iostream>
#include <function>
using namespace std;
...
class A {
public:
void fork() {
cout<<"Hello,World, This is A::fork"<<endl;
}
};
// Make a short name
using callback_type=std::function<void(int)>;

class B {
public:
void fork2(int val, const callback_type& cb) {
cout<<"Pretend to do something..."<<endl;
cout<<"Fire the callback:"<<endl;
cb(val);
}
};

int main() {
using namespace std::placeholders;

A a;
callback_type cb = std::bind(&A::fork, &a, _1);

cb(100);

B b;

b.fork2(200, cb);

b.fork2(200, [&](int x) {
cout<<"Try lambda as the callback, just likes JavaScript does."<<x<<endl;
});

return 0;
}


JavaScript Callback

There is nothing more than function, for callback in js.

Closure

A good thing is, from C++11, we do have the closure now, even it’s limited. An article about C++ closure can be found here. The bad thing is, it’s too limited to access the resources as will. The worse thing is, as crossing thread boundary, capturing the resource will fail. There is the worst thing: the compiler won’t tell you, everything looks fine, the syntax, the calling , until you get an access violation or other odd errors.

NOTE:

Explicitly declare the resources in the capture specification(in the []) if they will probably be used in another thread.

Closure When inter-operating C++ and JavaScript

When accessing js variables from C++ code in different thread, the context, which is crucial for js(or v8 engine), has changed. Then any access to these js variables involving the context using will fail. Extra effort must be needed to keep the variables information and build the running context.

Assuming the following js code:

// A is a node add-on
var a = new A();

// A::fork is a pure C++ function
a.fork(11, function(x) {
console.log('This is pure js callback');
});


And the implementation of
A::fork
is:

void fork(int x, const std::function<void(int)>& cb) {
/// Do something and fire cb in another thread.
cb(x);
}


Here is the node add-on for class A:

static void callFork(FunctionCallbackInfo<Value>& args) {
Isolate* iso = args.GetIsolate();
int x = args[0]->Int32Value();
Local<Value> cb_val = args[1];

// We need an extra structure to hold callback info
struct callback_info_struc {
Persistent<Function> cb;
};

// Have to use pointer form; Otherwise the cb will call
// constructor without parameters, and then compiler fails.
callback_info_struc* pcb_info = new callback_info_struc();
// Save the callback info.
pcb_info->cb.Reset(iso, cb_val);

// pa is a pointer to A object.
// Explicitly declare pcb_info in capture specification.
pa->fork(x, [&, pcb_info](int v) {
// Rebuild context
Isolate* iso = Isolate::GetCurrent();
HandleScope scope(iso);

// Prepare parameters.
Local<Value> params[1] = { Integer::New(iso, x) };

// Fire callback
pcb_info->cb->Call(iso->GetCurrentContext()->Global(), 1, params);

// Release persistent variable.
pcb_info->cb.Reset();

// Release callback info structure
delete pcb_info;
});
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: