建立異步操作組件:隊(duì)列和線程
6.25.2008
Kevin Lynx
引言
在一個(gè)高效的系統(tǒng)中,我們經(jīng)常會將一些費(fèi)時(shí)的操作轉(zhuǎn)換為異步操作。例如往數(shù)據(jù)庫中寫日志。如果數(shù)據(jù)庫
配置在網(wǎng)絡(luò)上,那么往數(shù)據(jù)庫中插入一些日志信息將非常慢(相對于程序其他部分)。
如何轉(zhuǎn)換為異步?
將類似于以上過程轉(zhuǎn)換為異步操作,一個(gè)典型的做法是:建立一個(gè)單獨(dú)的數(shù)據(jù)庫日志線程,一個(gè)線程安全的
隊(duì)列。要寫日志時(shí),只需要往隊(duì)列里放入數(shù)據(jù),數(shù)據(jù)庫日志線程則從這個(gè)隊(duì)列里取數(shù)據(jù)然后完成寫操作。
大致的過程類似于:




























將他們包裝起來
我們很有可能會在同一個(gè)系統(tǒng)中多次遇到類似需要轉(zhuǎn)換為異步操作的地方,如果每一次都手動去創(chuàng)建一個(gè)隊(duì)列和一
個(gè)線程,那將會多么乏味啊!懶惰的程序員喜歡重用各種代碼。所以,我自己覺得很有必要將這一切封裝起來。我
們只需要封裝這個(gè)隊(duì)列和創(chuàng)建線程的繁瑣細(xì)節(jié),讓應(yīng)用層全部專注于具體的邏輯處理:



















































我利用了已有的組件:線程安全的容器multi_list、包裝任意執(zhí)行體的functor、線程維護(hù)類thread。那么,現(xiàn)在,
應(yīng)用層只需要定義隊(duì)列節(jié)點(diǎn)類型,寫應(yīng)用相關(guān)的回調(diào)函數(shù)(任意可被functor包裝的廣義函數(shù))。(見附件例子)
之所以為這個(gè)組件加上init和release,是因?yàn)橛行〇|西(例如COM)需要在線程啟動時(shí)初始化,而在線程快結(jié)束時(shí)釋放,例如對于
使用COM的應(yīng)用來說,就需要在線程初始化時(shí)CoInitialize,結(jié)束時(shí)CoUninitialize。
閑說下其他東西
在本文的附件代碼里,你可以獲取到functor、thread、multi_list這些東西,所以我有必要提一下。
關(guān)于functor,你可以參看<實(shí)現(xiàn)functor - 增強(qiáng)型的函數(shù)指針>,基本上可以看成增強(qiáng)版的C回調(diào)函數(shù);至于multi_list,基本上
是一個(gè)container adapter (套用下STL的概念),使用條件變量參與線程同步,據(jù)說效率要比簡單的互斥高點(diǎn);至于thread,我需要
特別說下:
thread最為重要的就是為其附加了一個(gè)windows的消息隊(duì)列(只要調(diào)用PeekMessage之類的函數(shù)該隊(duì)列就存在),本意是可以讓其他線
程傳送數(shù)據(jù)到該線程,但是目前只用于線程退出,即其他線程可以在任何時(shí)候要求該線程安全地退出(該線程沒有阻塞的情況下,
阻塞時(shí)獲取不到消息)。我不知道這個(gè)安全退出策略是否真的有必要存在,但是我討厭看到各種撇腳的退出方法(例如設(shè)置全局標(biāo)志
變量,增加額外的--沒封裝前---event對象之類)。
結(jié)束
不知道其他人是如何做這種異步轉(zhuǎn)換操作的,在這里我只是起個(gè)拋磚引玉的作用,歡迎大家提出意見。
例子下載
posted on 2008-06-25 15:47 Kevin Lynx 閱讀(5062) 評論(29) 編輯 收藏 引用 所屬分類: 通用編程