寫過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代碼寫起來就舒服多了。