写过CTP的同窗可能很少,这是一个期货接口。没据说过的也无妨。node
CTP 提供了若干个父类供开发者继承,里面的回调都是经过覆盖父类的纯虚函数实现。 当SDK有事件发生的时候,就会调用这些定义的回调函数。c++
class CThostFtdcTraderSpi { public: virtual void OnFrontConnected(){}; virtual void OnFrontDisconnected(int nReason){};
编写一个这样的程序是十分痛苦的,由于回调函数的执行是在某个工做线程中。因此很容易引发并发读写的问题。代码会变得十分复杂。git
编写过Node.js的同窗必定以及十分习惯Node的单线程模式,回调函数执行的时候虽然有点“不一样步”,但好歹是在一个线程中,因此定义域里面的变量能够随便使用。用惯这种方便的编程方式的同窗,若是去接触一下C++那种多线程回调,必定会抓狂的。github
那么如何让CTP开发也能很舒服呢?或者干脆将CTP封装成Node的原生模块,而后在Node中调用,岂不妙哉。编程
这时候协调C++多线程和Nodejs单线程的关键角色就登场了,这就是libuv。多线程
#include <uv.h> uv_async_t async_t; uv_async_init(uv_default_loop(),&async_t,NULL);
咱们能够初始化一个默认的事件循环。 而后咱们能够把全部的回调虚函数都用下面的方式去实现并发
void uv_trader::OnFrontConnected() { CbRtnField* field = new CbRtnField(); field->eFlag = T_ON_CONNECT;//FrontConnected field->work.data = field; uv_queue_work(uv_default_loop(), &field->work, _on_async, _on_completed); }
其中_on_async是个空函数,忽略。_on_completed函数回在事件循环的时候触发,保证在主线程中调用。而后咱们在这个函数再去调用js的函数。async
void uv_trader::_on_completed(uv_work_t * work,int){ CbRtnField* cbTrnField = static_cast<CbRtnField*>(work->data); std::map<int, WrapTrader*>::iterator it = cb_map.find(cbTrnField->eFlag); if (it != cb_map.end()) { cb_map[cbTrnField->eFlag]->FunCallback(cbTrnField); } if (cbTrnField->rtnField) delete cbTrnField->rtnField; if (cbTrnField->rspInfo) delete cbTrnField->rspInfo; delete cbTrnField; }
除了释放资源,上面代码就是从一个存储着js回调函数的map中找到对应的js函数进行调用。函数
这些js函数都是在事先注册好的,就在nodejs中。oop
trader.on("connect",function(result){ console.log("on connected"); trader.reqUserLogin('','','',function(result,iRequestID){ console.log('login return val is '+result); }); });
js代码写起来就舒服多了。