Chaos網路庫(三) 主迴圈及非同步訊息的實現

2022-07-04 11:51:08 字數 3147 閱讀 6869

基本原理 -

在chaos開篇介紹(

)中已經提到,task service作為chaos庫的核心,主要承擔著三個重則:

1. 網路i/o

2. 超時事件

3. 非同步訊息處理

簡單來講,可以認為乙個task service中包含乙個epollfd,乙個定時事件管理器,乙個等待被處理的非同步訊息佇列

而task service會有乙個主迴圈來周而復始地執行這些任務(單執行緒 or 多執行緒,後續篇章再做分析),如圖:

注意: task service總是優先處理i/o事件,因為通常i/o事件都會牽涉到與使用者的互動,所以我們希望盡可能快地響應使用者

基本實現 -

對於i/o事件 和 超時事件 這裡不想熬述太多,i/o事件的處理無非就是利用底層的網路復用模型(例如epoll)返回響應的fd然後**,而超時事件的管理網上也有諸多方法,這裡task service採用的是std::priority_queue(堆結構),每次tick都會從堆中拿出最近事件來檢查是否超時

我們直接來關注非同步訊息的處理是如何實現的:

非同步訊息處理的關鍵在於:我們如何制定乙個通用的「非同步訊息體」,讓我們的task service看起來這些訊息體都是等同的,都是可執行的元素,但現實總是那麼的殘酷,通常我們總需要執行不同的任務,呼叫不同的函式,傳遞不同的引數型別和引數個數

很多動態語言可以通過closure

我們需要乙個closure來打包我們的非同步請求(函式和引數)

1. 它必須包含乙個任何宣告型別的函式執行體(函式指標)

2. 它可以裝入任何型別的引數

3. 它可以裝入任意個數的引數

對於需求1,我們有模板

對於需求2,我們有模板

對於需求3,我們有函式過載

是的,函式過載,但你一定會問,函式過載只能指定有限個引數,沒錯,我們一般只要提供最多10個左右的引數的函式過載就行了,畢竟誰會寫出那麼不結構化的**,想向乙個函式傳入十幾個以上的引數,如果有,那麼ta一定會被後續的維護人員牽腸掛肚。

我們直接來看chaos中實現:

templateclass async_method_bind_func_1_t: public async_method_base_t

async_method_bind_func_1_t(func func_, const arg0& arg0_)

: m_func1(func_),

m_arg0(arg0_)

virtual void exec()

private:

func m_func1;

arg0 m_arg0;

};

以上就是我們實現的乙個閉包,包含了乙個模板函式的指標,包含了乙個模板引數(要支援多個引數只需編寫多個過載介面即可),當呼叫exec函式時,該閉包就會被執行

ok,這個問題是否已經被解決了?不,還沒有,c++中存在著兩種函式,一種是和物件無關的(全域性/靜態),一種是和物件有關的(成員函式),我們上面只是解決了和物件無關的函式,接下來我們來看如何解決物件成員函式的打包

templateclass async_method_bind_obj_1_t: public async_method_base_t

async_method_bind_obj_1_t(t instance_, func func1_, const arg0& arg0_)

: m_instance(instance_),

m_func1(func1_),

m_arg0(arg0_)

virtual void exec()

private:

t m_instance;

func m_func1;

arg0 m_arg0;

};

我們只需多儲存乙個物件例項的位址,就能呼叫到其建構函式

這兩種實現方法都是繼承自同乙個基類,那麼對於task service來說,就有了統一的非同步訊息體的抽象,外界只要通過介面生成不同的async_method_base_t例項,然後投入到task service的佇列中,task service就能完成對這些非同步訊息的執行

介面使用 -

task service的使用也很簡單,對於我們上述的三種事件的處理,task service分別提供了三種不同的介面來供你註冊

class task_service_t : private noncopyable_t

;

這三個方法分別代表 註冊乙個i/o監聽事件,註冊乙個超時事件,投遞乙個非同步訊息

我們接下來看如何繫結乙個非同步訊息

//! 繫結乙個全域性/靜態函式,並投遞到task service中執行

task_service.post(

async_method_t::bind_func(

&test_static_func, tmp_str

));

//! 繫結乙個類中的靜態函式,並投遞到task service中執行

task_service.post(

async_method_t::bind_func(

&foo_t::test_static_func, tmp_str));

//! 繫結乙個物件的成員函式,並投遞到task service中執行

task_service.post(

async_method_t::bind_memfunc(

&hw, &hw_t::call1, 123456));

ps:chaos中的async_method實現相比boost::function以及c++ 11中的std::bind都要少很多功能,我不使用它們而自己實現的原因在於

1. 不想引入龐大的boost庫

2. 不希望chaos依賴於高版本的c++標準庫

3. 我希望實現乙個輕量級的,足以封裝非同步訊息的類,而不用像boost::function那樣做得面面俱到(話說回來boost::function確實很逆天:))

chaos庫的task service我就先講到這,之後我們再寫一篇關於task service高階的一些使用和注意細節

task service和async method的完整源**大家可到

Chaos網路庫(一) 開篇介紹

chaos是乙個基於linux平台,reactor模式的網路事件庫,目前僅支援tcp傳輸協議,僅在x86 64下編譯,並遵循3 clause bsd開源協議.在使用上,可以說它很像boost asio,可能是由於我對boost asio的介面設計很有愛吧,而且對於boost asio在非同步程式設計...

平台主資料庫支援型別及配置說明

1 主資料庫支援的型別 平台基礎資料庫只能用三種 sqlserver9,oracle,oracle11g,如下圖,可以採用三種不同的驅動來連線不同的資料庫,下面就三種不同驅動加以說明 sqlserver9 用於連線sqlserver2005 sqlserver2008及更新版本的sql server...

三種迴圈語句!及課後題

1.while語句,這裡不寫了,不懂的回頭看 2.dowhile 表示式 這是新學的,研究下 程式先執行do裡面的語句,再判斷while裡面的表示式真假,如果表示式值為真就回到do位置繼續重複執行do裡面的語句,為假則跳出迴圈繼續往下執行,型別其實跟單純的whil語句類似,但是在某些場合可能會發揮作...