libuv的典型應用——CTP的Node.js封裝

寫過CTP的同窗可能很少,這是一個期貨接口。沒據說過的也無妨。node

C++多線程回調

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

https://github.com/langhuihui/node-ctp

相關文章
相關標籤/搜索