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

寫過CTP的同學可能不多,這是一個期貨接口。沒聽說過的也無妨。

C++多線程回調

CTP 提供了若干個父類供開發者繼承,裏面的回調都是通過覆蓋父類的純虛函數實現。 當SDK有事件發生的時候,就會調用這些定義的回調函數。

class CThostFtdcTraderSpi
{
public:
	virtual void OnFrontConnected(){};
	virtual void OnFrontDisconnected(int nReason){};

編寫一個這樣的程序是十分痛苦的,因爲回調函數的執行是在某個工作線程中。所以很容易引起併發讀寫的問題。代碼會變得十分複雜。

編寫過Node.js的同學一定以及十分習慣Node的單線程模式,回調函數執行的時候雖然有點“不同步”,但好歹是在一個線程中,所以定義域裏面的變量可以隨便使用。用慣這種方便的編程方式的同學,如果去接觸一下C++那種多線程回調,一定會抓狂的。

那麼如何讓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的函數。

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中。

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章