日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

初学者:ACE学习

發(fā)布時(shí)間:2024/3/26 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 初学者:ACE学习 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

ACE的配置(window)

(使用VC++)安裝:

1. 從網(wǎng)上下載相應(yīng)源碼――――根據(jù)提示編輯config.h文件,并放置在ACE_ROOT\ace?目錄下。

2. 用VC打開(kāi)ACE_ROOT\ace\ace.dsw?,并編譯,編譯后會(huì)在ACE_ROOT\lib?目錄下生成兩個(gè)庫(kù):ACEd.dll(動(dòng)態(tài)庫(kù))和ACEd.lib(靜態(tài)庫(kù))。

3. 鏈接:把ACEd.dll(動(dòng)態(tài)庫(kù))和ACEd.lib(靜態(tài)庫(kù))復(fù)制到目錄ACE_ROOT\ace下,因?yàn)檫@是默認(rèn)的靜態(tài)庫(kù)鏈接路徑。或者可以修改靜態(tài)庫(kù)鏈接路徑:project->setting->link->object/library?填入ACE_ROOT\lib.

4.執(zhí)行:If?you?use?the?dynamic?libraries,?make?sure?you?include?ACE_ROOT\bin?in?your?PATH?whenever?you?run?programs?that

uses?ACE.?Otherwise?you?may?experience?problems?finding?ace.dll?or?aced.dll.

就是在程序執(zhí)行時(shí),如果使用ACE的動(dòng)態(tài)庫(kù),必須修改系統(tǒng)環(huán)境變量PATH的值,把包含ACEd.dll?的路徑添加到PATH中。修改如下:電腦屬性――高級(jí)――環(huán)境變量――系統(tǒng)變量――Path(修改)。或者把ACEd.dll?添加到系統(tǒng)默認(rèn)的搜索路徑之中,如添加到c:/window/system32?中。

在VC++下使用ACE

  新建工程:使用new菜單,選中project。選取win32?console?Applitation(控制臺(tái)應(yīng)用程序),建立一個(gè)空項(xiàng)目。同時(shí)新建一個(gè)workspace。

  一個(gè)workspace可以對(duì)應(yīng)幾個(gè)項(xiàng)目,一個(gè)項(xiàng)目對(duì)應(yīng)一個(gè)程序。當(dāng)然如何在一個(gè)workspace管理多個(gè)工程現(xiàn)在還沒(méi)搞清楚。Workspace保存空間中的相應(yīng)配置,而一個(gè)項(xiàng)目保存,自己項(xiàng)目下的項(xiàng)目配置。

  添加頭文件的搜索路徑:tools->option->directories,添加ace頭文件路徑。當(dāng)然,按照同樣的辦法,也可以修改庫(kù)文件、執(zhí)行文件、源文件的搜索路徑,只需做相應(yīng)選擇就可以了。

  修改項(xiàng)目的setting:通過(guò)project->setting進(jìn)入,或是直接在項(xiàng)目名字上點(diǎn)擊右鍵,選擇setting即可。把C/C++中的MLd修改為MDd(多線程);把link中input中的庫(kù)改為aced.lib,同時(shí)additional?path?中?http://www.cnblogs.com/../ace。這樣設(shè)置就基本完成。

注:以下摘抄自《ACE 程序員教程》

ACE簡(jiǎn)介

  ACE自適配通信環(huán)境?(Adaptive?Communication?Environment)是面向?qū)ο蟮臉?gòu)架和工具包,它為通信軟件實(shí)現(xiàn)了核心的并發(fā)和分布式模式。ACE中的組件可用于以下幾種目的:

·?并發(fā)和同步?

·?進(jìn)程間通信(IPC)?

·?內(nèi)存管理?

·?定時(shí)器?

·?信號(hào)?

·?文件系統(tǒng)管理?

·?線程管理?

·?事件多路分離和處理器分派?

·?連接建立和服務(wù)初始化?

·?軟件的靜態(tài)和動(dòng)態(tài)配置、重配置?

·?分層協(xié)議構(gòu)建和流式構(gòu)架?

·?分布式通信服務(wù):名字、日志、時(shí)間同步、事件路由和網(wǎng)絡(luò)鎖定,等等。

  目前ACE適用的OS平臺(tái)包括:實(shí)時(shí)OS(VxWorks、Chorus、LynxOS和pSoS)、大多數(shù)版本的UNIX(SunOS?4.x和5.x;?SGI?IRIX?5.x和6.x;?HP-UX?9.x,?10.x和11.x;?DEC?UNIX?3.x和4.x;?AIX?3.x和4.x;?DG/UX;?Linux;?SCO;?UnixWare;?NetBSD和FreeBSD)、Win32(使用MSVC++和Borland?C++的WinNT?3.5.x、4.x、Win95和WinCE)以及MVS?OpenEdition。

  在ACE構(gòu)架中有三個(gè)基本層次:

·?操作系統(tǒng)(OS)適配層?

·?C++包裝層?

·?構(gòu)架和模式層?

第2章 IPC?SAP:進(jìn)程間通信服務(wù)訪問(wèn)點(diǎn)包裝

  ACE_IPC_SAP類(lèi)提供的一些函數(shù)是所有IPC接口公有的。有四個(gè)不同的類(lèi)由此類(lèi)派生而出,每個(gè)類(lèi)各自代表ACE包含的一種IPC?SAP包裝類(lèi)屬。這些類(lèi)封裝適用于特定IPC接口的功能。例如,ACE_SOCK類(lèi)包含的功能適用于BSD?socket編程接口,而ACE_TLI包裝TLI編程接口。ACE_FIFO類(lèi)和???ACE_SPIPE類(lèi)。

socket類(lèi)屬(ACE_SOCK)

類(lèi)名

職責(zé)

ACE_SOCK_Acceptor

用于被動(dòng)的連接建立,基于BSD?accept()和listen()調(diào)用。

ACE_SOCK_Connector

用于主動(dòng)的連接建立,基于BSD?connect()調(diào)用。

ACE_SOCK_Dgram

用于提供基于UDP(用戶數(shù)據(jù)報(bào)協(xié)議)的無(wú)連接消息傳遞服務(wù)。封裝了sendto()和receivefrom()等調(diào)用,并提供了簡(jiǎn)單的send()和recv()接口。

ACE_SOCK_IO

用于提供面向連接的消息傳遞服務(wù)。封裝了send()、recv()和write()等調(diào)用。該類(lèi)是ACE_SOCK_Stream和ACE_SOCK_CODgram類(lèi)的基類(lèi)。

ACE_SOCK_Stream

用于提供基于TCP(傳輸控制協(xié)議)的面向連接的消息傳遞服務(wù)。派生自ACE_SOCK_IO,并提供了更多的包裝方法。

ACE_SOCK_CODgram

用于提供有連接數(shù)據(jù)報(bào)(connected?datagram)抽象。派生自ACE_SOCK_IO;它包含的open()方法使用bind()來(lái)綁定到指定的本地地址,并使用UDP連接到遠(yuǎn)地地址。

ACE_SOCK_Dgram_Mcast

用于提供基于數(shù)據(jù)報(bào)的多點(diǎn)傳送(multicast)抽象。包括預(yù)訂多點(diǎn)傳送組,以及發(fā)送和接收消息的方法

ACE_SOCK_Dgram_Bcast

用于提供基于數(shù)據(jù)報(bào)的廣播(broadcast)抽象。包括在子網(wǎng)中向所有接口廣播數(shù)據(jù)報(bào)消息的方法

          表2-1?ACE_SOCK中的類(lèi)及其職責(zé)

第3章?ACE的內(nèi)存管理

  ACE含有兩組不同的類(lèi)用于內(nèi)存管理。

  第一組是那些基于ACE_Allocator的類(lèi)。這組類(lèi)使用動(dòng)態(tài)綁定和策略模式來(lái)提供靈活性和可擴(kuò)展性。它們只能用于局部的動(dòng)態(tài)內(nèi)存分配。

  第二組類(lèi)基于ACE_Malloc模板類(lèi)。這組類(lèi)使用C++模板和外部多態(tài)性?(External?Polymorphism)來(lái)為內(nèi)存分配機(jī)制提供靈活性。在這組類(lèi)中的類(lèi)不僅包括了用于局部動(dòng)態(tài)內(nèi)存管理的類(lèi),也包括了管理進(jìn)程間共享內(nèi)存的類(lèi)。這些共享內(nèi)存類(lèi)使用底層OS(OS)共享內(nèi)存接口。

3.1?分配器(Allocator)

  分配器用于在ACE中提供一種動(dòng)態(tài)內(nèi)存管理機(jī)制。在ACE中有若干使用不同策略的分配器可用。這些不同策略提供相同的功能,但是具有不同的特性。所有的分配器都支持ACE_Allocator接口,因此無(wú)論是在運(yùn)行時(shí)還是在編譯時(shí),它們都可以很容易地相互替換。這也正是靈活性之所在。

分配器

描述

ACE_Allocator

ACE中的分配器類(lèi)的接口類(lèi)。這些類(lèi)使用繼承和動(dòng)態(tài)綁定來(lái)提供靈活性。

ACE_Static_Allocator

該分配器管理固定大小的內(nèi)存。每當(dāng)收到分配內(nèi)存的請(qǐng)求時(shí),它就移動(dòng)內(nèi)部指針、以返回內(nèi)存chunk(“大塊”)。它還假定內(nèi)存一旦被分配,就再也不會(huì)被釋放。

ACE_Cached_Allocator

該分配器預(yù)先分配內(nèi)存池,其中含有特定數(shù)目和大小的內(nèi)存chunk。這些chunk在內(nèi)部空閑表(free?list)中進(jìn)行維護(hù),并在收到內(nèi)存請(qǐng)求(malloc())時(shí)被返回。當(dāng)應(yīng)用調(diào)用free()時(shí),chunk被歸還到內(nèi)部空閑表、而不是OS中。

ACE_New_Allocator

為C++?new和delete操作符提供包裝的分配器,也就是,它在內(nèi)部使用new和delete操作符,以滿足動(dòng)態(tài)內(nèi)存請(qǐng)求。

              表3-1?ACE中的分配器

使用如下:

typedef?ACE_Cached_Allocator<MEMORY_BLOCK,ACE_SYNCH_MUTEX>?Allocator;

3.2?ACE_Malloc

  Malloc類(lèi)集使用模板類(lèi)ACE_Malloc來(lái)提供內(nèi)存管理。ACE_Malloc模板需要兩個(gè)參數(shù)(一個(gè)是內(nèi)存池,一個(gè)是池鎖),以產(chǎn)生我們的分配器類(lèi)。當(dāng)應(yīng)用發(fā)出free()調(diào)用時(shí),ACE_Malloc不會(huì)把所釋放的內(nèi)存返還給內(nèi)存池,而是由它自己的空閑表進(jìn)行管理。當(dāng)ACE_Malloc收到后續(xù)的內(nèi)存請(qǐng)求時(shí),它會(huì)使用空閑表來(lái)查找可返回的空block。因而,在使用ACE_Malloc時(shí),如果只發(fā)出簡(jiǎn)單的malloc()和free()調(diào)用,從OS分配的內(nèi)存數(shù)量將只會(huì)增加,不會(huì)減少。ACE_Malloc類(lèi)還含有一個(gè)remove()方法,用于發(fā)出請(qǐng)求給內(nèi)存池,將內(nèi)存返還給OS。該方法還將鎖也返還給OS。

3.2.2?使用ACE_Malloc

  ACE_Malloc類(lèi)的使用很簡(jiǎn)單。首先,用你選擇的內(nèi)存池和鎖定機(jī)制實(shí)例化ACE_Malloc,以創(chuàng)建分配器類(lèi)。隨后用該分配器類(lèi)實(shí)例化一個(gè)對(duì)象,這也就是你的應(yīng)用將要使用的分配器。當(dāng)你實(shí)例化分配器對(duì)象時(shí),傳給構(gòu)造器的第一個(gè)參數(shù)是一個(gè)字符串,它是你想要分配器對(duì)象使用的底層內(nèi)存池的“名字”。將正確的名字傳遞給構(gòu)造器非常重要,特別是如果你在使用共享內(nèi)存的話。否則,分配器將會(huì)為你創(chuàng)建一個(gè)新的內(nèi)存池。如果你在使用共享內(nèi)存池,這當(dāng)然不是你想要的,因?yàn)槟愀緵](méi)有獲得共享。

  為了方便底層內(nèi)存池的共享(重復(fù)一次,如果你在使用共享內(nèi)存的話,這是很重要的),ACE_Malloc類(lèi)還擁有一個(gè)映射(map)類(lèi)型接口:可被給每個(gè)被分配的內(nèi)存block一個(gè)名字,從而使它們可以很容易地被在內(nèi)存池中查找的另一個(gè)進(jìn)程找到。該接口含有bind()和find()調(diào)用。bind()調(diào)用用于給由malloc()調(diào)用返回給ACE_Malloc的block命名。find()調(diào)用,如你可能想到的那樣,用于查找與某個(gè)名字相關(guān)聯(lián)的內(nèi)存。

            表3-2列出了各種可用的內(nèi)存池:

池名

描述

ACE_MMAP_Memory_Pool

ACE_MMAP_MEMORY_POOL

使用<mmap(2)>創(chuàng)建內(nèi)存池。這樣內(nèi)存就可在進(jìn)程間共享了。每次更新時(shí),內(nèi)存都被更新到后備存儲(chǔ)(backing?store)。

ACE_Lite_MMAP_Memory_Pool

ACE_LITE_MMAP_MEMORY_POOL

使用<mmap(2)>創(chuàng)建內(nèi)存池。不像前面的映射,它不做后備存儲(chǔ)更新。代價(jià)是較低可靠性。

ACE_Sbrk_Memory_Pool

ACE_SBRK_MEMORY_POOL

使用<sbrk(2)>調(diào)用創(chuàng)建內(nèi)存池。

ACE_Shared_Memory_Pool

ACE_SHARED_MEMORY_POOL

使用系統(tǒng)V?<shmget(2)>調(diào)用創(chuàng)建內(nèi)存池。

Memory_Pool

?

內(nèi)存可在進(jìn)程間共享。

ACE_Local_Memory_Pool

ACE_LOCAL_MEMORY_POOL

通過(guò)C++的new和delete操作符創(chuàng)建局部?jī)?nèi)存池。該池不能在進(jìn)程間共享。

第4章?線程管理:ACE的同步和線程管理機(jī)制

  ACE_Thread提供了對(duì)OS的線程調(diào)用的簡(jiǎn)單包裝,這些調(diào)用處理線程創(chuàng)建、掛起、取消和刪除等問(wèn)題。它提供給應(yīng)用程序員一個(gè)簡(jiǎn)單易用的接口,可以在不同的線程API間移植。ACE_Thread是非常“瘦”的包裝,有著很少的開(kāi)銷(xiāo)。其大多數(shù)方法都是內(nèi)聯(lián)的,因而等價(jià)于對(duì)底層OS專(zhuān)有線程接口的直接調(diào)用。ACE_Thread中的所有方法都是靜態(tài)的,而且該類(lèi)一般不進(jìn)行實(shí)例化。

  線程是通過(guò)使用ACE_Thread::spawn_n()調(diào)用創(chuàng)建的。要作為線程的執(zhí)行啟動(dòng)點(diǎn)調(diào)用的函數(shù)的指針(在此例中為worker()函數(shù))被作為參數(shù)傳入該調(diào)用中。要注意的重點(diǎn)是ACE_Thread::spawn_n()要求所有的線程啟動(dòng)函數(shù)(方法)必須是靜態(tài)的或全局的(就如同直接使用OS線程API時(shí)所要求的一樣)。

  等待是通過(guò)使用ACE_Thread::join()調(diào)用來(lái)完成的。該方法的參數(shù)是你想要主線程與之聯(lián)接的線程的句柄(ACE_hthread_t)。

4.2?ACE同步原語(yǔ)

  ACE有若干可用于同步目的的類(lèi)。這些類(lèi)可劃分為以下范疇:

·?ACE?Lock類(lèi)屬?

·?ACE?Guard類(lèi)屬?

·?ACE?Condition類(lèi)屬?

·?雜項(xiàng)ACE?Synchronization類(lèi)?

名字

描述

ACE_Mutex

封裝互斥機(jī)制(根據(jù)平臺(tái),可以是mutex_t、pthread_mutex_t等等)的包裝類(lèi),用于提供簡(jiǎn)單而有效的機(jī)制來(lái)使對(duì)共享資源的訪問(wèn)序列化。它與二元信號(hào)量(binary?semaphore)的功能相類(lèi)似。可被用于線程和進(jìn)程間的互斥。

ACE_Thread_Mutex

可用于替換ACE_Mutex,專(zhuān)用于線程同步。

ACE_Process_Mutex

可用于替換ACE_Mutex,專(zhuān)用于進(jìn)程同步。

ACE_NULL_Mutex

提供了ACE_Mutex接口的“無(wú)為”(do-nothing)實(shí)現(xiàn),可在不需要同步時(shí)用作替換(單線程使用)。

ACE_RW_Mutex

封裝讀者/作者鎖的包裝類(lèi)。它們是分別為讀和寫(xiě)進(jìn)行獲取的鎖,在沒(méi)有作者在寫(xiě)的時(shí)候,多個(gè)讀者可以同時(shí)進(jìn)行讀取。

ACE_RW_Thread_Mutex

可用于替換ACE_RW_Mutex,專(zhuān)用于線程同步。

ACE_RW_Process_Mutex

可用于替換ACE_RW_Mutex,專(zhuān)用于進(jìn)程同步。

ACE_Semaphore

這些類(lèi)實(shí)現(xiàn)計(jì)數(shù)信號(hào)量,在有固定數(shù)量的線程可以同時(shí)訪問(wèn)一個(gè)資源時(shí)很有用。在OS不提供這種同步機(jī)制的情況下,可通過(guò)互斥體來(lái)進(jìn)行模擬。

ACE_Thread_Semaphore

應(yīng)被用于替換ACE_Semaphore,專(zhuān)用于線程同步。

ACE_Process_Semaphore

應(yīng)被用于替換ACE_Semaphore,專(zhuān)用于進(jìn)程同步。

ACE_Token

提供“遞歸互斥體”(recursive?mutex),也就是,當(dāng)前持有某令牌的線程可以多次重新獲取它,而不會(huì)阻塞。而且,當(dāng)令牌被釋放時(shí),它確保下一個(gè)正阻塞并等待此令牌的線程就是下一個(gè)被放行的線程。

ACE_Null_Token

令牌接口的“無(wú)為”(do-nothing)實(shí)現(xiàn),在你知道不會(huì)出現(xiàn)多個(gè)線程時(shí)使用。

ACE_Lock

定義鎖定接口的接口類(lèi)。一個(gè)純虛類(lèi),如果使用的話,必須承受虛函數(shù)調(diào)用開(kāi)銷(xiāo)。

ACE_Lock_Adapter

基于模板的適配器,允許將前面提到的任意一種鎖定機(jī)制適配到ACE_Lock接口。

            表4-1?ACE鎖類(lèi)屬中的類(lèi)

  表4-1中描述的類(lèi)都支持同樣的接口。但是,在任何繼承層次中,這些類(lèi)都是互不關(guān)聯(lián)的。在ACE中,鎖通常用模板來(lái)參數(shù)化,因?yàn)?#xff0c;在大多數(shù)情況下,使用虛函數(shù)調(diào)用的開(kāi)銷(xiāo)都是不可接受的。使用模板使得程序員可獲得相當(dāng)程度的靈活性。他可以在編譯時(shí)(但不是在運(yùn)行時(shí))選擇他想要使用的的鎖定機(jī)制的類(lèi)型。然而,在某些情形中,程序員仍可能需要使用動(dòng)態(tài)綁定和替換(substitution);對(duì)于這些情況,ACE提供了ACE_Lock和ACE_Lock_Adapter類(lèi)。

  在臨界區(qū)內(nèi)完成的工作使用ACE_Thread_Mutex互斥體對(duì)象進(jìn)行保護(hù)。該對(duì)象由主線程作為參數(shù)傳給工作者線程。臨界區(qū)控制是通過(guò)在ACE_Thread_Mutex對(duì)象上發(fā)出acquire()調(diào)用,從而獲取互斥體的所有權(quán)來(lái)完成的。一旦互斥體被獲取,沒(méi)有其他線程能夠再進(jìn)入這一代碼區(qū)。臨界區(qū)控制是通過(guò)使用release()調(diào)用來(lái)釋放的。一旦互斥體的所有權(quán)被放棄,就會(huì)喚醒所有其他在等待的線程。這些線程隨即相互競(jìng)爭(zhēng),以獲得互斥體的所有權(quán)。第一個(gè)試圖獲取所有權(quán)的線程會(huì)進(jìn)入臨界區(qū)。

使用示例:

struct?Args

{

public:Args(int?iterations):?mutex_(),iterations_(iterations){}

ACE_Thread_Mutex?mutex_;

int?iterations_;

};

4.2.1.3?使用令牌(Token)

  如表4-1中所提到的,ACE_Token類(lèi)提供所謂的“遞歸互斥體”,它可以被最初獲得它的同一線程進(jìn)行多次重新獲取。ACE_Token類(lèi)還確保所有試圖獲取它的線程按嚴(yán)格的FIFO(先進(jìn)先出)順序排序。

  遞歸鎖允許同一線程多次獲取同一個(gè)鎖。線程不會(huì)因?yàn)樵噲D獲取它已經(jīng)擁有的鎖而死鎖。這些類(lèi)型的鎖能在各種不同的情況下派上用場(chǎng)。例如,如果你用一個(gè)鎖來(lái)維護(hù)跟蹤流的一致性,你可能希望這個(gè)鎖是遞歸的,因?yàn)槟硞€(gè)方法可以調(diào)用一個(gè)跟蹤例程,獲取鎖,被信號(hào)中斷,然后再?lài)L試獲取這個(gè)跟蹤鎖。如果鎖是非遞歸的,線程將會(huì)在這里鎖住它自己。你會(huì)發(fā)現(xiàn)很多其他需要遞歸鎖的有趣應(yīng)用。重要的是要記住,你獲取遞歸鎖多少次,就必須釋放它多少次。

  在SunOS?5.x上運(yùn)行例4-3,釋放鎖的線程常常也是重新獲得它的線程(大約90%的情況是這樣)。但是如果你采用ACE_Token類(lèi)作為鎖定機(jī)制來(lái)運(yùn)行這個(gè)例子,每個(gè)線程都會(huì)輪流獲得令牌,然后有序地把機(jī)會(huì)讓給下一個(gè)線程。

  盡管ACE_Token作為所謂的遞歸鎖非常有用,它們實(shí)際上是更大的“令牌管理”構(gòu)架的一部分。該構(gòu)架允許你維護(hù)數(shù)據(jù)存儲(chǔ)中數(shù)據(jù)的一致性。

4.2.2?ACE守衛(wèi)(Guard)類(lèi)屬

  ACE中的守衛(wèi)用于自動(dòng)獲取和釋放鎖。守衛(wèi)類(lèi)的對(duì)象定義一個(gè)代碼塊,在其上獲取一個(gè)鎖。在退出此代碼塊時(shí),鎖被自動(dòng)釋放。

  ACE中的守衛(wèi)類(lèi)是一種模板,它通過(guò)所需鎖定機(jī)制的類(lèi)型來(lái)參數(shù)化。底層的鎖可以是ACE?Lock類(lèi)屬中的任何類(lèi),也就是,任何互斥體或鎖類(lèi)。它是這樣工作的:對(duì)象的構(gòu)造器獲取鎖,析構(gòu)器釋放鎖。表4-2列出了ACE中可用的守衛(wèi):

?

名字

描述

ACE_Guard

自動(dòng)在底層鎖上調(diào)用acquire()和release()。任何ACE?Lock類(lèi)屬中的鎖都可以作為它的模板參數(shù)傳入。

ACE_Read_Guard

自動(dòng)在底層鎖上調(diào)用acquire()和release()。

ACE_Write_Guard

自動(dòng)在底層鎖上調(diào)用acquire()和release()。

            表4-2?ACE中的守衛(wèi)

4.2.3?ACE條件(Condition)類(lèi)屬

  ACE_Condition類(lèi)是針對(duì)OS條件變量原語(yǔ)的包裝類(lèi)。線程常常需要特定條件被滿足才能繼續(xù)它的操作。條件變量不是被用作互斥原語(yǔ),而是用作特定條件已經(jīng)滿足的指示器。在使用條件變量時(shí),你的程序應(yīng)該完成以下步驟:

·?獲取全局資源(例如,消息隊(duì)列)的鎖(互斥體)。?

·?檢查條件(例如,消息隊(duì)列里有空間嗎?)。?

·?如果條件失敗,調(diào)用條件變量的wait()方法。等待在未來(lái)?xiàng)l件變?yōu)檎妗?

·?當(dāng)另一線程在全局資源上執(zhí)行操作時(shí),它發(fā)信號(hào)(signal())給所有其他在此資源上測(cè)試條件的線程(例如,另一線程從消息隊(duì)列中取出一個(gè)消息,然后通過(guò)條件變量發(fā)送信號(hào),以使阻塞在wait()上的線程能夠再?lài)L試將它們的消息插入隊(duì)列)。?

·?在醒來(lái)之后,重新檢查條件現(xiàn)在是否為真。如為真,則在全局資源上執(zhí)行操作(例如,將消息插入全局消息隊(duì)列)?

  需要特別注意的是,在阻塞wait調(diào)用中之前,條件變量機(jī)制(也就是ACE_Cond)負(fù)責(zé)釋放全局資源上的互斥體。如果沒(méi)有進(jìn)行此操作,將沒(méi)有其他的線程能夠在此資源上工作(該資源是條件改變的原因)。同樣,一旦阻塞線程收到信號(hào)、重又醒來(lái),它在檢查條件之前會(huì)在內(nèi)部重新獲取鎖。

  注意主線程首先獲取一個(gè)互斥體,然后對(duì)條件進(jìn)行測(cè)試。如果條件不為真,主線程就等待在此條件變量上。條件變量隨即自動(dòng)釋放互斥體,并使主線程進(jìn)入睡眠。條件變量總是像這樣與互斥體一起使用。這是一種可如下描述的一般模式[1]:

    while(?expression?NOT?TRUE?)?wait?on?condition?variable;

  記住條件變量不是用于互斥,而是用于我們所描述的發(fā)送信號(hào)功能。

4.2.4?雜項(xiàng)同步類(lèi)

  除了上面描述的同步類(lèi),ACE還包括其他一些同步類(lèi),比如ACE_Barrier和ACE_Atomic_Op。

4.2.4.1?ACE中的柵欄(Barrier)

  柵欄有一個(gè)好名字,因?yàn)樗∏械孛枋隽藮艡趹?yīng)做的事情。一組線程可以使用柵欄來(lái)進(jìn)行共同的相互同步。組中的每個(gè)線程各自執(zhí)行,直到到達(dá)柵欄,就阻塞在那里。在所有相關(guān)線程到達(dá)柵欄后,它們就全部繼續(xù)它們的執(zhí)行。就是說(shuō),它們一個(gè)接一個(gè)地阻塞,等待其他的線程到達(dá)柵欄;一旦所有線程都到達(dá)了它們的執(zhí)行路徑中的“柵欄點(diǎn)”,它們就一起重新啟動(dòng)。

  在ACE中,柵欄在ACE_Barrier類(lèi)中實(shí)現(xiàn)。在柵欄對(duì)象被實(shí)例化時(shí),它將要等待的線程的數(shù)目會(huì)作為參數(shù)傳入。一旦到達(dá)執(zhí)行路徑中的“柵欄點(diǎn)”,每個(gè)線程都在柵欄對(duì)象上發(fā)出wait()調(diào)用。它們?cè)谶@里阻塞,直到其他線程到達(dá)它們各自的“柵欄點(diǎn)”,然后再一起繼續(xù)執(zhí)行。當(dāng)柵欄從相關(guān)線程那里接收了適當(dāng)數(shù)目的wait()調(diào)用時(shí),它就同時(shí)喚醒所有阻塞的線程。

4.2.4.2?原子操作(Atomic?Op)

  ACE_Atomic_Op類(lèi)用于將同步透明地參數(shù)化進(jìn)基本的算術(shù)運(yùn)算中。ACE_Atomic_Op是一種模板類(lèi),鎖定機(jī)制和需要參數(shù)化的類(lèi)型被作為參數(shù)傳入其中。ACE是這樣來(lái)實(shí)現(xiàn)此機(jī)制的:重載所有算術(shù)操作符,并確保在操作前獲取鎖,在操作后釋放它。運(yùn)算本身被委托給通過(guò)模板傳入的的類(lèi)。

4.3?使用ACE_THREAD_MANAGER進(jìn)行線程管理

  我們可以使用ACE_Thread包裝類(lèi)來(lái)創(chuàng)建和銷(xiāo)毀線程。但是,該包裝類(lèi)的功能比較有限。ACE_Thread_Manager提供了ACE_Thread中的功能的超集。特別地,它增加了管理功能,以使啟動(dòng)、取消、掛起和恢復(fù)一組相關(guān)線程變得更為容易。它用于創(chuàng)建和銷(xiāo)毀成組的線程和任務(wù)(ACE_Task是一種比線程更高級(jí)的構(gòu)造,可在ACE中用于進(jìn)行多線程編程。我們將在后面再來(lái)討論任務(wù))。它還提供了這樣的功能:發(fā)送信號(hào)給一組線程,或是在一組線程上等待,而不是像我們?cè)谇懊娴睦又兴吹降哪菢?#xff0c;以一種不可移植的方式來(lái)調(diào)用join()。

4.4?線程專(zhuān)有存儲(chǔ)(Thread?Specific?Storage)

  對(duì)于各個(gè)線程來(lái)說(shuō),可能需要不同的全局或靜態(tài)數(shù)據(jù)。可使用線程專(zhuān)有存儲(chǔ)來(lái)滿足此需求。像輸入端口這樣的結(jié)構(gòu)可放在線程專(zhuān)有存儲(chǔ)中,并可像邏輯上的靜態(tài)或全局變量一樣被訪問(wèn);而實(shí)際上它對(duì)線程來(lái)說(shuō)是私有的。

  傳統(tǒng)上,線程專(zhuān)有存儲(chǔ)通過(guò)讓人迷惑的底層操作系統(tǒng)API來(lái)實(shí)現(xiàn)。在ACE中,TSS通過(guò)使用ACE_TSS模板類(lèi)來(lái)實(shí)現(xiàn)。需要成為線程專(zhuān)有的類(lèi)被傳入ACE_TSS模板,然后可以使用C++的->操作符來(lái)調(diào)用它的全部公共方法。

第5章?任務(wù)和主動(dòng)對(duì)象(Active?Object):并發(fā)編程模式(多線程)

5.1?主動(dòng)對(duì)象

  那么到底什么是主動(dòng)對(duì)象呢?傳統(tǒng)上,所有的對(duì)象都是被動(dòng)的代碼段,對(duì)象中的代碼是在對(duì)它發(fā)出方法調(diào)用的線程中執(zhí)行的。也就是,調(diào)用線程(calling?threads)被“借出”,以執(zhí)行被動(dòng)對(duì)象的方法。

  而主動(dòng)對(duì)象卻不一樣。這些對(duì)象持有它們自己的線程(甚或多個(gè)線程),并將這個(gè)線程用于執(zhí)行對(duì)它們的任何方法的調(diào)用。因而,如果你想象一個(gè)傳統(tǒng)對(duì)象,在里面封裝了一個(gè)線程(或多個(gè)線程),你就得到了一個(gè)主動(dòng)對(duì)象。

  例如,設(shè)想對(duì)象“A”已在你的程序的main()函數(shù)中被實(shí)例化。當(dāng)你的程序啟動(dòng)時(shí),OS創(chuàng)建一個(gè)線程,以從main()函數(shù)開(kāi)始執(zhí)行。如果你調(diào)用對(duì)象A的任何方法,該線程將“流過(guò)”那個(gè)方法,并執(zhí)行其中的代碼。一旦執(zhí)行完成,該線程返回調(diào)用該方法的點(diǎn)并繼續(xù)它的執(zhí)行。但是,如果”A”是主動(dòng)對(duì)象,事情就不是這樣了。在這種情況下,主線程不會(huì)被主動(dòng)對(duì)象借用。相反,當(dāng)”A”的方法被調(diào)用時(shí),方法的執(zhí)行發(fā)生在主動(dòng)對(duì)象持有的線程中。另一種思考方法:如果調(diào)用的是被動(dòng)對(duì)象的方法(常規(guī)對(duì)象),調(diào)用會(huì)阻塞(同步的);而另一方面,如果調(diào)用的是主動(dòng)對(duì)象的方法,調(diào)用不會(huì)阻塞(異步的)。

5.2?ACE_Task

  ACE_Task是ACE中的任務(wù)或主動(dòng)對(duì)象“處理結(jié)構(gòu)”的基類(lèi)。在ACE中使用了此類(lèi)來(lái)實(shí)現(xiàn)主動(dòng)對(duì)象模式。所有希望成為“主動(dòng)對(duì)象”的對(duì)象都必須從此類(lèi)派生。你也可以把ACE_TASK看作是更高級(jí)的、更為面向?qū)ο蟮木€程類(lèi)。

  當(dāng)我們?cè)谇耙徽轮惺褂肁CE_Thread包裝時(shí),你一定已經(jīng)注意到了一些“不好”之處。那一章中的大多數(shù)程序都被分解為函數(shù)、而不是對(duì)象。這是因?yàn)锳CE_Thread包裝需要一個(gè)全局函數(shù)名、或是靜態(tài)方法作為參數(shù)。隨后該函數(shù)(靜態(tài)方法)就被用作所派生的線程的“啟動(dòng)點(diǎn)”。這自然就使得程序員要為每個(gè)線程寫(xiě)一個(gè)函數(shù)。如我們已經(jīng)看到的,這可能會(huì)導(dǎo)致非面向?qū)ο蟮某绦蚍纸狻?/p>

  相反,ACE_Task處理的是對(duì)象,因而在構(gòu)造OO程序時(shí)更便于思考。因此,在大多數(shù)情況下,當(dāng)你需要構(gòu)建多線程程序時(shí),較好的選擇是使用ACE_Task的子類(lèi)。這樣做有若干好處。首要的是剛剛所提到的,這可以產(chǎn)生更好的OO軟件。其次,你不必操心你的線程入口是否是靜態(tài)的,因?yàn)锳CE_Task的入口是一個(gè)常規(guī)的成員函數(shù)。而且,我們會(huì)看到ACE_Task還包括了一種用于與其他任務(wù)進(jìn)行通信的易于使用的機(jī)制。

  重申剛才所說(shuō)的,ACE_Task可用作:

·?更高級(jí)的線程(我們稱(chēng)之為任務(wù))。?

·?主動(dòng)對(duì)象模式中的主動(dòng)對(duì)象。?

  ACE_Task的結(jié)構(gòu):每個(gè)任務(wù)都含有一或多個(gè)線程,以及一個(gè)底層消息隊(duì)列。各個(gè)任務(wù)通過(guò)這些消息隊(duì)列進(jìn)行通信。但是,消息隊(duì)列并非是程序員需要關(guān)注的對(duì)象。發(fā)送任務(wù)可以使用putq()調(diào)用來(lái)將消息插入到另一任務(wù)的消息隊(duì)列中。隨后接收任務(wù)就可以通過(guò)使用getq()調(diào)用來(lái)從它自己的消息隊(duì)列里將消息提取出來(lái)。

5.2.2?創(chuàng)建和使用任務(wù)

  要?jiǎng)?chuàng)建任務(wù)或主動(dòng)對(duì)象,必須從ACE_Task類(lèi)派生子類(lèi)。在子類(lèi)派生之后,必須采取以下步驟:

·?實(shí)現(xiàn)服務(wù)初始化和終止方法:open()方法應(yīng)該包含所有專(zhuān)屬于任務(wù)的初始化代碼。其中可能包括諸如連接控制塊、鎖和內(nèi)存這樣的資源。close()方法是相應(yīng)的終止方法。?

·?調(diào)用啟用(Activation)方法:在主動(dòng)對(duì)象實(shí)例化后,你必須通過(guò)調(diào)用activate()啟用它。要在主動(dòng)對(duì)象中創(chuàng)建的線程的數(shù)目,以及其他一些參數(shù),被傳遞給activate()方法。activate()方法會(huì)使svc()方法成為所有它生成的線程的啟動(dòng)點(diǎn)。?

·?實(shí)現(xiàn)服務(wù)專(zhuān)有的處理方法:如上面所提到的,在主動(dòng)對(duì)象被啟用后,各個(gè)新線程在svc()方法中啟動(dòng)(如何區(qū)分并調(diào)用不同線程)。應(yīng)用開(kāi)發(fā)者必須在子類(lèi)中定義此方法。?

5.2.3?任務(wù)間通信

  如前面所提到的,ACE中的每個(gè)任務(wù)都有一個(gè)底層消息隊(duì)列。這個(gè)消息隊(duì)列被用作任務(wù)間通信的一種方法。當(dāng)一個(gè)任務(wù)想要與另一任務(wù)“談話”時(shí),它創(chuàng)建一個(gè)消息,并將此消息放入(putq())它想要與之談話的任務(wù)的消息隊(duì)列。接收任務(wù)通常用getq()從消息隊(duì)列里獲取消息。如果隊(duì)列中沒(méi)有數(shù)據(jù)可用,它就進(jìn)入休眠狀態(tài)。如果有其他任務(wù)將消息插入它的隊(duì)列,它就會(huì)蘇醒過(guò)來(lái),從隊(duì)列中拾取數(shù)據(jù)并處理它。因而,在這種情況下,接收任務(wù)將從發(fā)送任務(wù)那里接收消息,并以應(yīng)用特定的方式作出反饋。

5.3?主動(dòng)對(duì)象模式(Active?Object?Pattern)

  主動(dòng)對(duì)象模式用于降低方法執(zhí)行和方法調(diào)用之間的耦合。該模式描述了另外一種更為透明的任務(wù)間通信方法。

  該模式使用ACE_Task類(lèi)作為主動(dòng)對(duì)象。在這個(gè)對(duì)象上調(diào)用方法時(shí),它就像是常規(guī)對(duì)象一樣。就是說(shuō),方法調(diào)用是通過(guò)同樣的->操作符來(lái)完成的,其不同在于這些方法的執(zhí)行發(fā)生于封裝在ACE_Task中的線程內(nèi)。在使用被動(dòng)或主動(dòng)對(duì)象進(jìn)行編程時(shí),客戶程序看不到什么區(qū)別,或僅僅是很小的區(qū)別。對(duì)于構(gòu)架開(kāi)發(fā)者來(lái)說(shuō),這是非常有用的,因?yàn)殚_(kāi)發(fā)者需要使構(gòu)架客戶與構(gòu)架的內(nèi)部結(jié)構(gòu)屏蔽開(kāi)來(lái)。這樣構(gòu)架用戶就不必去擔(dān)心線程、同步、會(huì)合點(diǎn)(rendezvous),等等。

5.3.1?主動(dòng)對(duì)象模式工作原理

  主動(dòng)對(duì)象模式是ACE實(shí)現(xiàn)的較為復(fù)雜的模式中的一個(gè)。該模式有如下參與者:

1.?主動(dòng)對(duì)象(基于ACE_Task)。?

2.?ACE_Activation_Queue。?

3.?若干ACE_Method_Object(主動(dòng)對(duì)象的每個(gè)方法都需要有一個(gè)方法對(duì)象)。?

4.?若干ACE_Future對(duì)象(每個(gè)要返回結(jié)果的方法都需要這樣一個(gè)對(duì)象)。?

  我們已經(jīng)看到,ACE_Task是怎樣創(chuàng)建和封裝線程的。要使ACE_Task成為主動(dòng)對(duì)象,需要完成一些額外的工作:

  必須為所有要從客戶異步調(diào)用的方法編寫(xiě)方法對(duì)象。每個(gè)方法對(duì)象都派生自ACE_Method_Object,并會(huì)實(shí)現(xiàn)它的call()方法。每個(gè)方法對(duì)象還維護(hù)上下文信息(比如執(zhí)行方法所需的參數(shù),以及用于獲取返回值的ACE_Future對(duì)象。這些值作為私有屬性維護(hù))。你可以把方法對(duì)象看作是方法調(diào)用的“罩子”(closure)。客戶發(fā)出方法調(diào)用,使得相應(yīng)的方法對(duì)象被實(shí)例化,并被放入啟用隊(duì)列(activation?queue)中。方法對(duì)象是命令(Command)模式的一種形式(參見(jiàn)有關(guān)設(shè)計(jì)模式的參考文獻(xiàn))。

  ACE_Activation_Queue是一個(gè)隊(duì)列,方法對(duì)象在等待執(zhí)行時(shí)被放入其中。因而啟用隊(duì)列中含有所有等待調(diào)用的方法(以方法對(duì)象的形式)。封裝在ACE_Task中的線程保持阻塞,等待任何方法對(duì)象被放入啟用隊(duì)列。一旦有方法對(duì)象被放入,任務(wù)就將該方法對(duì)象取出,并調(diào)用它的call()方法。call()方法應(yīng)該隨即調(diào)用該方法在ACE_Task中的相應(yīng)實(shí)現(xiàn)。在方法實(shí)現(xiàn)返回后,call()方法在ACE_Future對(duì)象中設(shè)置(set())所獲得的結(jié)果。

  客戶使用ACE_Future對(duì)象獲取它在主動(dòng)對(duì)象上發(fā)出的任何異步操作的結(jié)果。一旦客戶發(fā)出異步調(diào)用,立即就會(huì)返回一個(gè)ACE_Future對(duì)象。于是客戶就可以在任何它喜歡的時(shí)候去嘗試從ACE_Future對(duì)象中獲取結(jié)果。如果客戶試圖在結(jié)果被設(shè)置之前從ACE_Future對(duì)象中提取結(jié)果,客戶將會(huì)阻塞。如果客戶不希望阻塞,它可以通過(guò)使用ready()調(diào)用來(lái)輪詢(xún)(poll)ACE_Future對(duì)象。如果結(jié)果已被設(shè)置,該方法返回1;否則就返回0。ACE_Future對(duì)象基于“多態(tài)期貨”(polymorphic?futures)的概念。

  call()方法的實(shí)現(xiàn)應(yīng)該將返回的ACE_Future對(duì)象的內(nèi)部值設(shè)置為從調(diào)用實(shí)際的方法實(shí)現(xiàn)所獲得的結(jié)果(這個(gè)實(shí)際的方法實(shí)現(xiàn)在ACE_Task中編寫(xiě))。

第6章?反應(yīng)堆(Reactor):用于事件多路分離和分派的體系結(jié)構(gòu)模式(事件驅(qū)動(dòng)-異步事件)

  反應(yīng)堆本質(zhì)上提供一組更高級(jí)的編程抽象,簡(jiǎn)化了事件驅(qū)動(dòng)的分布式應(yīng)用的設(shè)計(jì)和實(shí)現(xiàn)。除此而外,反應(yīng)堆還將若干不同種類(lèi)的事件的多路分離集成到易于使用的API中。特別地,反應(yīng)堆對(duì)基于定時(shí)器的事件、信號(hào)事件、基于I/O端口監(jiān)控的事件和用戶定義的通知進(jìn)行統(tǒng)一地處理。

  ACE中的反應(yīng)堆與若干內(nèi)部和外部組件協(xié)同工作。其基本概念是反應(yīng)堆構(gòu)架檢測(cè)事件的發(fā)生(通過(guò)在OS事件多路分離接口上進(jìn)行偵聽(tīng)),并發(fā)出對(duì)預(yù)登記事件處理器(event?handler)對(duì)象中的方法的“回調(diào)”(callback)。該方法由應(yīng)用開(kāi)發(fā)者實(shí)現(xiàn),其中含有應(yīng)用處理此事件的特定代碼。于是用戶(也就是,應(yīng)用開(kāi)發(fā)者)必須:

1.?創(chuàng)建事件處理器,以處理他所感興趣的某事件。?

2.?在反應(yīng)堆上登記,通知說(shuō)他有興趣處理某事件,同時(shí)傳遞他想要用以處理此事件的事件處理器的指針給反應(yīng)堆。?

  隨后反應(yīng)堆構(gòu)架將自動(dòng)地:

1.?在內(nèi)部維護(hù)一些表,將不同的事件類(lèi)型與事件處理器對(duì)象關(guān)聯(lián)起來(lái)。?

2.?在用戶已登記的某個(gè)事件發(fā)生時(shí),反應(yīng)堆發(fā)出對(duì)處理器中相應(yīng)方法的回調(diào)。?

6.2?事件處理器

  反應(yīng)堆模式在ACE中被實(shí)現(xiàn)為ACE_Reactor類(lèi),它提供反應(yīng)堆構(gòu)架的功能接口。

  如上面所提到的,反應(yīng)堆將事件處理器對(duì)象作為服務(wù)提供者使用。一旦反應(yīng)堆成功地多路分離和分派了某事件,事件處理器對(duì)象就對(duì)它進(jìn)行處理。因此,反應(yīng)堆會(huì)在內(nèi)部記住當(dāng)特定類(lèi)型的事件發(fā)生時(shí),應(yīng)該回調(diào)哪一個(gè)事件處理器對(duì)象。當(dāng)應(yīng)用在反應(yīng)堆上登記它的處理器對(duì)象,以處理特定類(lèi)型的事件時(shí),反應(yīng)堆會(huì)創(chuàng)建這種事件和相應(yīng)的事件處理器的關(guān)聯(lián)。

  因?yàn)榉磻?yīng)堆需要記錄哪一個(gè)事件處理器將被回調(diào),它需要知道所有事件處理器對(duì)象的類(lèi)型。這是通過(guò)替換模式(Substitution?Pattern)的幫助來(lái)實(shí)現(xiàn)的(或者換句話說(shuō),通過(guò)“是……類(lèi)型”(is?a?type?of)變種繼承)。該構(gòu)架提供名為ACE_Event_Handler的抽象接口類(lèi),所有應(yīng)用特有的事件處理器都必須由此派生(這使得應(yīng)用特有的處理器都具有相同的類(lèi)型,即ACE_Event_Handler,所以它們可以相互替換)。

ACE_Event_Handler類(lèi)擁有若干不同的“handle”(處理)方法,每個(gè)處理方法被用于處理不同種類(lèi)的事件。當(dāng)應(yīng)用程序員對(duì)特定事件感興趣時(shí),他就對(duì)ACE_Event_Handler類(lèi)進(jìn)行子類(lèi)化,并實(shí)現(xiàn)他感興趣的處理方法。如上面所提到的,隨后他就在反應(yīng)堆上為特定事件“登記”他的事件處理器類(lèi)。于是反應(yīng)堆就會(huì)保證在此事件發(fā)生時(shí),自動(dòng)回調(diào)在適當(dāng)?shù)氖录幚砥鲗?duì)象中的適當(dāng)?shù)摹県andle”方法。

  使用ACE_Reactor基本上有三個(gè)步驟:

·?創(chuàng)建ACE_Event_Handler的子類(lèi),并在其中實(shí)現(xiàn)適當(dāng)?shù)摹癶andle_”方法,以處理你想要此事件處理器為之服務(wù)的事件類(lèi)型。(參看表6-1來(lái)確定你需要實(shí)現(xiàn)哪一個(gè)“handle_”方法。注意你可以使用同一個(gè)事件處理器對(duì)象處理多種類(lèi)型的事件,因而可以重載多于一個(gè)的“handle_”方法。)?

·?通過(guò)調(diào)用反應(yīng)堆對(duì)象的register_handler(),將你的事件處理器登記到反應(yīng)堆。?

·?在事件發(fā)生時(shí),反應(yīng)堆將自動(dòng)回調(diào)相應(yīng)的事件處理器對(duì)象的適當(dāng)?shù)摹癶andle_”方法。

ACE_Event_Handler中的處理方法

在子類(lèi)中重載,所處理事件的類(lèi)型:

?

handle_signal()

信號(hào)。當(dāng)任何在反應(yīng)堆上登記的信號(hào)發(fā)生時(shí),反應(yīng)堆自動(dòng)回調(diào)該方法。

handle_input()

來(lái)自I/O設(shè)備的輸入。當(dāng)I/O句柄(比如UNIX中的文件描述符)上的輸入可用時(shí),反應(yīng)堆自動(dòng)回調(diào)該方法。

handle_exception()

異常事件。當(dāng)已在反應(yīng)堆上登記的異常事件發(fā)生時(shí)(例如,如果收到SIGURG(緊急信號(hào))),反應(yīng)堆自動(dòng)回調(diào)該方法。

handle_timeout()

定時(shí)器。當(dāng)任何已登記的定時(shí)器超時(shí)的時(shí)候,反應(yīng)堆自動(dòng)回調(diào)該方法。

handle_output()

I/O設(shè)備輸出。當(dāng)I/O設(shè)備的輸出隊(duì)列有可用空間時(shí),反應(yīng)堆自動(dòng)回調(diào)該方法。

      表6-1?ACE_Event_Handler中的處理方法及其對(duì)應(yīng)事件

6.2.1?事件處理器登記

  登記事件處理器、以處理特定事件,是在反應(yīng)堆上調(diào)用register_handler()方法來(lái)完成的。register_handler()方法是重載方法,就是說(shuō),實(shí)際上有若干方法可用于登記不同的事件類(lèi)型,每個(gè)方法都叫做register_handler()。但是它們有著不同的特征:它們的參數(shù)各不相同。基本上,register_handler()方法采用handle/event_handle元組或signal/event_handler元組作為參數(shù),并將它們加入反應(yīng)堆的內(nèi)部分派表。當(dāng)有事件在handle上發(fā)生時(shí),反應(yīng)堆在它的內(nèi)部分派表中查找相應(yīng)的event_handler,并自動(dòng)在它找到的event_handler上回調(diào)適當(dāng)?shù)姆椒ā?/p>

6.2.2?事件處理器的拆除和生存期管理

  一旦所需的事件被處理后,可能就無(wú)需再讓事件處理器登記在反應(yīng)堆上。因而,反應(yīng)堆提供了從它的內(nèi)部分派表中拆除事件處理器的技術(shù)。一旦事件處理器被拆除,它就不再會(huì)被反應(yīng)堆回調(diào)。把這樣的死掉的句柄從反應(yīng)堆里拆除是很重要的,因?yàn)?#xff0c;如果不這樣做,反應(yīng)堆將會(huì)把此句柄標(biāo)記為“讀就緒”,并會(huì)持續(xù)不斷地回調(diào)此事件處理器的handle_方法。

6.2.2.1?從反應(yīng)堆內(nèi)部分派表中隱式拆除事件處理器

  隱式拆除是更為常用的從反應(yīng)堆中拆除事件處理器的技術(shù)。事件處理器的每個(gè)“handle_”方法都會(huì)返回一個(gè)整數(shù)給反應(yīng)堆。如果此整數(shù)為0,在處理器方法完成后、事件處理器將保持在反應(yīng)堆上的登記。但是,如果“handle_”方法返回的整數(shù)<0,反應(yīng)堆將自動(dòng)回調(diào)此事件處理器的handle_close()方法,并將它從自己的內(nèi)部分派表中拆除。handle_close()方法用于執(zhí)行處理器特有的任何清除工作,它們需要在事件處理器被拆除前完成;其中可以包括像刪除處理器申請(qǐng)的動(dòng)態(tài)內(nèi)存、或關(guān)閉日志文件這樣的工作

6.2.2.2從反應(yīng)堆內(nèi)部分派表中顯式拆除事件處理器

  另一種從反應(yīng)堆的內(nèi)部表中拆除事件處理器的方法是顯式地調(diào)用反應(yīng)堆的remove_handler()方法集。該方法也是重載方法,就像register_handler()一樣。它采用需要拆除的處理器的句柄或信號(hào)號(hào)碼作為參數(shù),并將該處理器從反應(yīng)堆的內(nèi)部分派表中拆除。在remove_handler()被調(diào)用時(shí),反應(yīng)堆還自動(dòng)調(diào)用事件處理器的handle_close()方法。可以這樣來(lái)對(duì)其進(jìn)行控制:將ACE_Event_Handler::DONT_CALL掩碼傳給remove_handler(),從而使得handle_close()方法不會(huì)被調(diào)用。

6.3?通過(guò)反應(yīng)堆進(jìn)行事件處理

6.3.1?I/O事件多路分離

  通過(guò)在具體的事件處理器類(lèi)中重載handle_input()方法,反應(yīng)堆可用于處理基于I/O設(shè)備的輸入事件。這樣的I/O可以發(fā)生在磁盤(pán)文件、管道、FIFO或網(wǎng)絡(luò)socket上。為了進(jìn)行基于I/O設(shè)備的事件處理,反應(yīng)堆在內(nèi)部使用從操作系統(tǒng)獲取的設(shè)備句柄(在基于UNIX的系統(tǒng)中,該句柄是在文件或socket打開(kāi)時(shí),OS返回的文件描述符。在Windows中該局柄是由Windows返回的設(shè)備句柄)。網(wǎng)絡(luò)應(yīng)用顯然是最適于這樣的多路分離的應(yīng)用之一。下面的例子演示反應(yīng)堆是怎樣與具體接受器一起使用來(lái)構(gòu)造一個(gè)服務(wù)器的。

?

#include "ace/Reactor.h"#include "ace/SOCK_Acceptor.h"#define PORT_NO 1024typedef ACE_SOCK_Acceptor Acceptor;//forward declarationclass My_Accept_Handler;class My_Input_Handler: public ACE_Event_Handler{public://ConstructorMy_Input_Handler(){ACE_DEBUG((LM_DEBUG,"Constructor\n"));}//Called back to handle any input receivedint handle_input(ACE_HANDLE){//receive the datapeer_.recv_n(data,12);ACE_DEBUG((LM_DEBUG,"%s\n",data));// do something with the input received.// ...//keep yourself registered with the reactorreturn 0;}//Used by the reactor to determine the underlying handleACE_HANDLE get_handle() const{return this->peer_.get_handle();//return this->peer_i().get_handle();}//Returns a reference to the underlying stream.ACE_SOCK_Stream &peer_i(){return this->peer_;}ACE_SOCK_Stream peer_; //publicprivate://ACE_SOCK_Stream peer_;char data [12];};class My_Accept_Handler: public ACE_Event_Handler{public://ConstructorMy_Accept_Handler(ACE_Addr &addr){this->open(addr);}//Open the peer_acceptor so it starts to ”listen”//for incoming clients.int open(ACE_Addr &addr){peer_acceptor.open(addr);return 0;}//Overload the handle input methodint handle_input(ACE_HANDLE handle){//Client has requested connection to server.//Create a handler to handle the connectionMy_Input_Handler *eh = new My_Input_Handler();//Accept the connection "into" the Event Handlerif (this->peer_acceptor.accept (eh->peer_, // stream0, // remote address0, // timeout1) ==-1) //restart if interrupted{ACE_DEBUG((LM_ERROR,"Error in connection\n"));}ACE_DEBUG((LM_DEBUG,"Connection established\n"));//Register the input event handler for readingACE_Reactor::instance()->register_handler(eh,ACE_Event_Handler::READ_MASK);//Unregister as the acceptor is not expecting new clientsreturn -1;}//Used by the reactor to determine the underlying handleACE_HANDLE get_handle(void) const{return this->peer_acceptor.get_handle();}private:Acceptor peer_acceptor;};int main(int argc, char * argv[]){//Create an address on which to receive connectionsACE_INET_Addr addr(PORT_NO);//Create the Accept Handler which automatically begins to “l(fā)isten”//for client requests for connectionsMy_Accept_Handler *eh=new My_Accept_Handler(addr);//Register the reactor to call back when incoming client connectsACE_Reactor::instance()->register_handler(eh,ACE_Event_Handler::ACCEPT_MASK);//Start the event loopwhile(1){ACE_Reactor::instance()->handle_events();}return 0;}

?

  第一個(gè)具體事件處理器My_Accept_Handler用于接受和建立從客戶到來(lái)的連接。另一個(gè)事件處理器是My_Input_Handler,它用于在連接建立后對(duì)連接進(jìn)行處理。因而,My_Accept_Handler接受連接,并將實(shí)際的處理委托給My_Input_Handler。

  我們首先創(chuàng)建了一個(gè)ACE_INET_Addr地址對(duì)象,將我們希望在其上接受連接的端口作為參數(shù)傳給它。其次,實(shí)例化一個(gè)類(lèi)型為My_Accept_Handler的對(duì)象。隨后地址對(duì)象通過(guò)My_Accept_Handler的構(gòu)造器傳遞給它。My_Accept_Handler有一個(gè)用于連接建立的底層“具體接受器”(在講述“IPC”的一章中有與具體接受器相關(guān)的內(nèi)容)。My_Accept_Handler的構(gòu)造器將對(duì)新連接的“偵聽(tīng)”委托給該具體接受器的open()方法。在處理器開(kāi)始偵聽(tīng)連接后,它在反應(yīng)堆上登記,通知說(shuō)在接收到新連接請(qǐng)求時(shí),它需要被回調(diào)。為完成此操作,我們采用ACE_Event_Handler::ACCEPT_MASK掩碼調(diào)用register_handler()。

  當(dāng)反應(yīng)堆被告知要登記處理器時(shí),它執(zhí)行“雙重分派”來(lái)確定事件處理器的底層句柄。為完成此操作,它調(diào)用get_handler()方法。因?yàn)榉磻?yīng)堆使用get_handle()方法來(lái)確定底層流的句柄,在My_Accept_Handler中必須實(shí)現(xiàn)get_handle()方法。在此例中,我們簡(jiǎn)單地調(diào)用具體接受器的get_handle(),它會(huì)將適當(dāng)?shù)木浔祷亟o反應(yīng)堆。

  一旦在該句柄上接收到新的連接請(qǐng)求,反應(yīng)堆會(huì)自動(dòng)地回調(diào)My_Accept_Handler的handle_input()方法。隨后Accept?Handler(接受處理器)實(shí)例化一個(gè)新的Input?Handler(輸入處理器),并調(diào)用具體接受器的accept()方法來(lái)實(shí)際地建立連接。注意Input?Handler底層的流是作為accept()調(diào)用的第一個(gè)參數(shù)傳入的。這使得新實(shí)例化的Input?Handler中的流被設(shè)置為在連接建立(由accept()完成)后立即創(chuàng)建的新流。隨后Accept?Handler將Input?Handler登記到反應(yīng)堆,通知它如果有任何可讀的輸入就進(jìn)行回調(diào)(使用ACE_Event_Handler::READ_MASK)。隨后接受處理器返回-1,使自己從反應(yīng)堆的內(nèi)部事件分派表中被拆除。

  現(xiàn)在,如果有任何輸入從客戶到達(dá),反應(yīng)堆將自動(dòng)回調(diào)My_Input_Handler::handle_input()。注意在My_Input_Handler的handle_input()方法中,返回給反應(yīng)堆是0。這指示我們希望保持它的登記;反之在My_Accept_Handler中我們?cè)谒膆andle_input()中返回-1,以確保它被注銷(xiāo)。

  除了在上面的例子中使用的READ_MASK和ACCEPT_MASK而外,還有若干其他的掩碼,可在登記或是拆除處理器時(shí)使用。這些掩碼如表6-2所示,它們可與register_handler()和remove_handler()方法一起使用。每個(gè)掩碼保證反應(yīng)堆回調(diào)事件處理器時(shí)的不同行為方式,通常這意味著不同的“handle”方法會(huì)被回調(diào)。

掩碼

回調(diào)方法

何時(shí)

和……一起使用

ACE_Event_Handler::READ_MASK

handle_input()

在句柄上有數(shù)據(jù)可讀時(shí)。

register_handler()

ACE_Event_Handler::WRITE_MASK

handle_output()

在I/O設(shè)備輸出緩沖區(qū)上有可用空間、并且新數(shù)據(jù)可以發(fā)送給它時(shí)。

register_handler()

ACE_Event_Handler::TIMER_MASK

handle_close()

傳給handle_close()以指示調(diào)用它的原因是超時(shí)。

接受器和連接器的handle_timeout方法。反應(yīng)堆不使用此掩碼。

ACE_Event_Handler::ACCEPT_MASK

handle_input()

在OS內(nèi)部的偵聽(tīng)隊(duì)列上收到了客戶的新連接請(qǐng)求時(shí)。

register_handler()

ACE_Event_Handler::CONNECT_MASK

handle_input()

在連接已經(jīng)建立時(shí)。

register_handler()

ACE_Event_Handler::DONT_CALL

None.

在反應(yīng)堆的remove_handler()被調(diào)用時(shí)保證事件處理器的handle_close()方法不被調(diào)用。

remove_handler()

                表6-2?反應(yīng)堆中的掩碼

6.4?定時(shí)器(Timer)

  反應(yīng)堆還包括了調(diào)度定時(shí)器的方法,它們?cè)诔瑫r(shí)的時(shí)候回調(diào)適當(dāng)?shù)氖录幚砥鞯膆andle_timeout()方法。為調(diào)度這樣的定時(shí)器,反應(yīng)堆擁有一個(gè)schedule_timer()方法。該方法接收事件處理器(該事件處理器的handle_timeout()方法將會(huì)被回調(diào))、以及以ACE_Time_value對(duì)象形式出現(xiàn)的延遲作為參數(shù)。此外,還可以指定時(shí)間間隔,使定時(shí)器在它超時(shí)后自動(dòng)被復(fù)位。

  反應(yīng)堆在內(nèi)部維護(hù)ACE_Timer_Queue,它以定時(shí)器要被調(diào)度的順序?qū)λ鼈冞M(jìn)行維護(hù)。實(shí)際使用的用于保存定時(shí)器的數(shù)據(jù)結(jié)構(gòu)可以通過(guò)反應(yīng)堆的set_timer_queue()方法進(jìn)行改變。反應(yīng)堆有若干不同的定時(shí)器結(jié)構(gòu)可用,包括定時(shí)器輪(timer?wheel)、定時(shí)器堆(timer?heap)和哈希式定時(shí)器輪(hashed?timer?wheel)。這些內(nèi)容將在后面的部分詳細(xì)討論。

6.4.1?ACE_Time_Value

  ACE_Time_Value是封裝底層OS平臺(tái)的日期和時(shí)間結(jié)構(gòu)的包裝類(lèi)。它基于在大多數(shù)UNIX操作系統(tǒng)上都可用的timeval結(jié)構(gòu);該結(jié)構(gòu)存儲(chǔ)以秒和微秒計(jì)算的絕對(duì)時(shí)間。

  其他的OS平臺(tái),比如POSIX和Win32,使用略有不同的表示方法。該類(lèi)封裝這些不同,并提供了可移植的C++接口。

  ACE_Time_Value類(lèi)使用運(yùn)算符重載,提供簡(jiǎn)單的算術(shù)加、減和比較。該類(lèi)中的方法會(huì)對(duì)時(shí)間量進(jìn)行“規(guī)范化”(normalize)。所謂規(guī)范化,是將timeval結(jié)構(gòu)中的兩個(gè)域調(diào)整為規(guī)范化的編碼方式;這種編碼方式可以確保精確的比較

首先通過(guò)實(shí)現(xiàn)事件處理器Time_Handler的handle_timeout()方法,將其設(shè)置用以處理超時(shí)。主函數(shù)實(shí)例化Time_Handler類(lèi)型的對(duì)象,并使用反應(yīng)堆的schedule_timer()方法調(diào)度多個(gè)定時(shí)器(10個(gè))。handle_timeout方法需要以下參數(shù):指向?qū)⒈换卣{(diào)的處理器的指針、定時(shí)器超時(shí)時(shí)間,以及一個(gè)將在handle_timeout()方法被回調(diào)時(shí)發(fā)送給它的參數(shù)。每次調(diào)用schedule_timer(),它都返回一個(gè)唯一的定時(shí)器標(biāo)識(shí)符,并隨即存儲(chǔ)在timer_id[]數(shù)組里。這個(gè)標(biāo)識(shí)符可用于在任何時(shí)候取消該定時(shí)器。在上面的例子中也演示了定時(shí)器的取消:在所有定時(shí)器被初始調(diào)度后,程序通過(guò)調(diào)用反應(yīng)堆的cancel_timer()方法(使用相應(yīng)的timer_id作為參數(shù))取消了第五個(gè)定時(shí)器。

6.4.3?使用不同的定時(shí)器隊(duì)列

  不同的環(huán)境可能需要不同的調(diào)度和取消定時(shí)器的方法。在下面的任一條件為真時(shí),實(shí)現(xiàn)定時(shí)器的算法的性能就會(huì)成為一個(gè)問(wèn)題:

·?需要細(xì)粒度的定時(shí)器。?

·?在某一時(shí)刻未完成的定時(shí)器的數(shù)目可能會(huì)非常大。?

·?算法使用過(guò)于昂貴的硬件中斷來(lái)實(shí)現(xiàn)。?

  ACE允許用戶從若干在ACE中已存在的定時(shí)器中進(jìn)行選擇,或是根據(jù)為定時(shí)器定義的接口開(kāi)發(fā)他們自己的定時(shí)器。表6-3詳細(xì)列出了ACE中可用的各種定時(shí)器: 

定時(shí)器

數(shù)據(jù)結(jié)構(gòu)描述

性能

ACE_Timer_Heap

定時(shí)器存儲(chǔ)在優(yōu)先級(jí)隊(duì)列的堆實(shí)現(xiàn)中。

schedule_timer()的開(kāi)銷(xiāo)=O(lg?n)

cancel_timer()的開(kāi)銷(xiāo)=O(lg?n)

查找當(dāng)前定時(shí)器的開(kāi)銷(xiāo)=O(1)

ACE_Timer_List

定時(shí)器存儲(chǔ)在雙向鏈表中。

schedule_timer()的開(kāi)銷(xiāo)=O(n)

cancel_timer()的開(kāi)銷(xiāo)=O(1)

查找當(dāng)前定時(shí)器的開(kāi)銷(xiāo)=O(1)

ACE_Timer_Hash

在這里使用的這種結(jié)構(gòu)是定時(shí)器輪算法的變種。性能高度依賴(lài)于所用的哈希函數(shù)。

schedule_timer()的開(kāi)銷(xiāo)=最壞=O(n)?最佳=O(1)

cancel_timer()的開(kāi)銷(xiāo)=O(1)

查找當(dāng)前定時(shí)器的開(kāi)銷(xiāo)=O(1)

ACE_Timer_Wheel

定時(shí)器存儲(chǔ)在“數(shù)組指針”(pointers?to?arrays)的數(shù)組中。每個(gè)被指向的數(shù)組都已排序。

schedule_timer()的開(kāi)銷(xiāo)=最壞=O(n)

cancel_timer()的開(kāi)銷(xiāo)=O(1)

查找當(dāng)前定時(shí)器的開(kāi)銷(xiāo)=O(1)

            表6-3?ACE中的定時(shí)器

6.5?處理信號(hào)(Signal)

  如我們?cè)诶?-1中所看到的,反應(yīng)堆含有進(jìn)行信號(hào)處理的方法。處理信號(hào)的事件處理器應(yīng)重載handle_signal()方法,因?yàn)樵摲椒▽⒃谛盘?hào)發(fā)生時(shí)被回調(diào)。要為信號(hào)登記處理器,可以使用多個(gè)register_handler()方法中的一個(gè),就如同例6-1中所演示的那樣。如果對(duì)特定信號(hào)不再感興趣,通過(guò)調(diào)用remove_handler(),處理器可以被拆除,并恢復(fù)為先前安裝的信號(hào)處理器。反應(yīng)堆在內(nèi)部使用sigaction()系統(tǒng)調(diào)用來(lái)設(shè)置和恢復(fù)信號(hào)處理器。通過(guò)使用ACE_Sig_Handlers類(lèi)和與其相關(guān)聯(lián)的方法,無(wú)需反應(yīng)堆也可以進(jìn)行信號(hào)處理。

  使用反應(yīng)堆進(jìn)行信號(hào)處理和使用ACE_Sig_Handlers類(lèi)的重要區(qū)別是基于反應(yīng)堆的機(jī)制只允許應(yīng)用給每個(gè)信號(hào)關(guān)聯(lián)一個(gè)事件處理器,而ACE_Sig_Handlers類(lèi)允許在信號(hào)發(fā)生時(shí),回調(diào)多個(gè)事件處理器。

6.6?使用通知(Notification)

  反應(yīng)堆不僅可以在系統(tǒng)事件發(fā)生時(shí)發(fā)出回調(diào),也可以在用戶定義的事件發(fā)生時(shí)回調(diào)處理器。這是通過(guò)反應(yīng)堆的“通知”接口來(lái)完成的;該接口由兩個(gè)方法組成:notify()和max_notify_iterations()。

  通過(guò)使用notify()方法,可以明確地指示反應(yīng)堆對(duì)特定的事件處理器對(duì)象發(fā)出回調(diào)。在反應(yīng)堆與消息隊(duì)列、或是協(xié)作任務(wù)協(xié)同使用時(shí),這是十分有用的。可在ASX構(gòu)架組件與反應(yīng)堆一起使用時(shí)找到這種用法的一些好例子。

max_notify_iterations()方法通知反應(yīng)堆,每次只完成指定次數(shù)的“迭代”(iterations)。也就是說(shuō),在一次handle_events()調(diào)用中只處理指定數(shù)目的“通知”。因而如果使用max_notify_iterations()將迭代的次數(shù)設(shè)置為20,而又有25個(gè)通知同時(shí)到達(dá),handle_events()方法一次將只處理這些通知中的20個(gè)。剩下的五個(gè)通知將在handle_events()下一次在事件循環(huán)中被調(diào)用時(shí)再處理。

  事件處理循環(huán)中值得注意的一個(gè)主要區(qū)別是,程序傳遞給handle_events()一個(gè)ACE_Time_Value。如果在此時(shí)間內(nèi)沒(méi)有事件發(fā)生,handle_events()方法就會(huì)結(jié)束。在handle_events()結(jié)束后,perform_notification()被調(diào)用,它使用反應(yīng)堆的notify()方法來(lái)請(qǐng)求反應(yīng)堆通知處理器(它是在事件發(fā)生時(shí)被作為參數(shù)傳入的)。隨后反應(yīng)堆就使用所收到的掩碼來(lái)執(zhí)行對(duì)處理器的適當(dāng)“handle”方法的調(diào)用。在此例中,通過(guò)傳遞ACE_Event_Handler::READ_MASK,我們使用notify()來(lái)通知我們的事件處理器有輸入,從而使得反應(yīng)堆回調(diào)該處理器的handle_input()方法。因?yàn)槲覀円褜ax_notify_iterations設(shè)為5,所以在一次handle_events()調(diào)用過(guò)程中反應(yīng)堆實(shí)際上只會(huì)發(fā)出5個(gè)通知。

第7章?接受器(Acceptor)和連接器(Connector):連接建立模式

  接受器/連接器模式設(shè)計(jì)用于降低連接建立與連接建立后所執(zhí)行的服務(wù)之間的耦合。因?yàn)樵撃J浇档土朔?wù)和連接建立方法之間的耦合,非常容易改動(dòng)其中一個(gè),而不影響另外一個(gè),從而也就可以復(fù)用以前編寫(xiě)的連接建立機(jī)制和服務(wù)例程的代碼。

7.1?接受器模式

  在ACE中,接收器模式借助名為ACE_Acceptor的“工廠”(Factory)實(shí)現(xiàn)。工廠(通常)是用于對(duì)助手對(duì)象的實(shí)例化過(guò)程進(jìn)行抽象的類(lèi)。在面向?qū)ο笤O(shè)計(jì)中,復(fù)雜的類(lèi)常常會(huì)將特定功能委托給助手類(lèi)。復(fù)雜的類(lèi)對(duì)助手的創(chuàng)建和委托必須很靈活。這種靈活性是在工廠的幫助下獲得的。工廠允許一個(gè)對(duì)象通過(guò)改變它所委托的對(duì)象來(lái)改變它的底層策略,而工廠提供給應(yīng)用的接口卻是一樣的,這樣,可能根本就無(wú)需對(duì)客戶代碼進(jìn)行改動(dòng)(有關(guān)工廠的更多信息,請(qǐng)閱讀“設(shè)計(jì)模式”中的參考文獻(xiàn))。

  ACE_Acceptor工廠允許應(yīng)用開(kāi)發(fā)者改變“助手”對(duì)象,以用于:

·?被動(dòng)連接建立?

·?連接建立后的處理?

  同樣地,ACE_Connector工廠允許應(yīng)用開(kāi)發(fā)者改變“助手”對(duì)象,以用于:

·?主動(dòng)連接建立?

·?連接建立后的處理?

  ACE_Acceptor被實(shí)現(xiàn)為模板容器,通過(guò)兩個(gè)類(lèi)作為實(shí)參來(lái)進(jìn)行實(shí)例化。第一個(gè)參數(shù)實(shí)現(xiàn)特定的服務(wù)(類(lèi)型為ACE_Event_Handler。因?yàn)樗挥糜谔幚鞩/O事件,所以必須來(lái)自事件處理類(lèi)層次),應(yīng)用在建立連接后執(zhí)行該服務(wù);第二個(gè)參數(shù)是“具體的”接受器(可以是在IPC_SAP一章中討論的各種變種)。

  特別要注意的是ACE_Acceptor工廠和底層所用的具體接受器是非常不同的。具體接受器可完全獨(dú)立于ACE_Acceptor工廠使用,而無(wú)需涉及我們?cè)谶@里討論的接受器模式(獨(dú)立使用接受器已在IPC_SAP一章中討論和演示)。ACE_Acceptor工廠內(nèi)在于接受器模式,并且不能在沒(méi)有底層具體接受器的情況下使用。ACE_Acceptor使用底層的具體接受器來(lái)建立連接。如我們已看到的,有若干ACE的類(lèi)可被用作ACE_Acceptor工廠模板的第二個(gè)參數(shù)(也就是,具體接受器類(lèi))。但是服務(wù)處理類(lèi)必須由應(yīng)用開(kāi)發(fā)者來(lái)實(shí)現(xiàn),而且其類(lèi)型必須是ACE_Event_Handler。ACE_Acceptor工廠可以這樣來(lái)實(shí)例化: 

  typedef?ACE_Acceptor<My_Service_Handler,ACE_SOCK_ACCEPTOR>?MyAcceptor;

  這里,名為My_Service_Handler的事件處理器和具體接受器ACE_SOCK_ACCEPTOR被傳給MyAcceptor。ACE_SOCK_ACCEPTOR是基于BSD?socket流家族的TCP接受器(各種可傳給接受器工廠的不同類(lèi)型的接受器,見(jiàn)表7-1和IPC一章)。請(qǐng)?jiān)俅巫⒁?#xff0c;在使用接受器模式時(shí),我們總是處理兩個(gè)接受器:名為ACE_Acceptor的工廠接受器,和ACE中的某種具體接受器,比如ACE_SOCK_ACCEPTOR(你可以創(chuàng)建自定義的具體接受器來(lái)取代ACE_SOCK_ACCEPTOR,但你將很可能無(wú)需改變ACE_Acceptor工廠類(lèi)中的任何東西)。

  重要提示:ACE_SOCK_ACCEPTOR實(shí)際上是一個(gè)宏,其定義為: 

  #define?ACE_SOCK_ACCEPTOR?ACE_SOCK_Acceptor,?ACE_INET_Addr

  我們認(rèn)為這個(gè)宏的使用是必要的,因?yàn)樵陬?lèi)中的typedefs在某些平臺(tái)上無(wú)法工作。如果不是這樣的話,ACE_Acceptor就可以這樣來(lái)實(shí)例化: 

  typedef?ACE_Acceptor<My_Service_Handler,ACE_SOCK_Acceptor>MyAcceptor;

7.1.1?組件

  如上面的討論所說(shuō)明的,在接受器模式中有三個(gè)主要的參與類(lèi):

  ·?具體接受器:它含有建立連接的特定策略,連接與底層的傳輸協(xié)議機(jī)制系在一起。下面是在ACE中的各種具體接受器的例子:ACE_SOCK_ACCEPTOR(使用TCP來(lái)建立連接)、ACE_LSOCK_ACCEPTOR(使用UNIX域socket來(lái)建立連接),等等。?

  ·?具體服務(wù)處理器:由應(yīng)用開(kāi)發(fā)者編寫(xiě),它的open()方法在連接建立后被自動(dòng)回調(diào)。接受器構(gòu)架假定服務(wù)處理類(lèi)的類(lèi)型是    ACE_Event_Handler,這是ACE定義的接口類(lèi)(該類(lèi)已在反應(yīng)堆一章中詳細(xì)討論過(guò))。另一個(gè)特別為接受器和連接器模式的服務(wù)處理而創(chuàng)建的類(lèi)是ACE_Svc_Handler。該類(lèi)不僅基于ACE_Event_Handler接口(這是使用反應(yīng)堆所必需的),同時(shí)還基于在ASX流構(gòu)架中使用的ACE_Task類(lèi)。ACE_Task類(lèi)提供的功能有:創(chuàng)建分離的線程、使用消息隊(duì)列來(lái)存儲(chǔ)到來(lái)的數(shù)據(jù)消息、并發(fā)地處理它們,以及其他一些有用的功能。如果與接受器模式一起使用的具體服務(wù)處理器派生自ACE_Svc_Handler、而不是ACE_Event_Handler,它就可以獲得這些額外的功能。對(duì)ACE_Svc_Handler中的額外功能的使用,在這一章的高級(jí)課程里詳細(xì)討論。在下面的討論中,我們將使用ACE_Svc_Handler作為我們的事件處理器。在簡(jiǎn)單的ACE_Event_Handler和ACE_Svc_Handler類(lèi)之間的重要區(qū)別是,后者擁有一個(gè)底層通信流組件。這個(gè)流在ACE_Svc_Handler模板被實(shí)例化的時(shí)候設(shè)置。而在使用ACE_Event_Handler的情況下,我們必須自己增加I/O通信端點(diǎn)(也就是,流對(duì)象),作為事件處理器的私有數(shù)據(jù)成員。因而,在這樣的情況下,應(yīng)用開(kāi)發(fā)者應(yīng)該將他的服務(wù)處理器創(chuàng)建為ACE_Svc_Handler類(lèi)的子類(lèi),并首先實(shí)現(xiàn)將被構(gòu)架自動(dòng)回調(diào)的open()方法。此外,因?yàn)锳CE_Svc_Handler是一個(gè)模板,通信流組件和鎖定機(jī)制是作為模板參數(shù)被傳入的。?

  ·?反應(yīng)堆:與ACE_Acceptor協(xié)同使用。如我們將看到的,在實(shí)例化接受器后,我們啟動(dòng)反應(yīng)堆的事件處理循環(huán)。反應(yīng)堆,如先前所解釋的,是一個(gè)事件分派類(lèi);而在此情況下,它被接受器用于將連接建立事件分派到適當(dāng)?shù)姆?wù)處理例程。?

接受器類(lèi)型

所用地址

所用流

具體接受器

TCP流接受器

ACE_INET_Addr

ACE_SOCK_STREAM

ACE_SOCK_ACCEPTOR

UNIX域本地流socket接受器

ACE_UNIX_Addr

ACE_LSOCK_STREAM

ACE_LSOCK_ACCEPTOR

管道作為底層通信機(jī)制

ACE_SPIPE_Addr

ACE_SPIPE_STREAM

ACE_SPIPE_ACCEPTOR

          表7-1?ACE中的連接建立機(jī)制

7.2?連接器

  連接器與接受器非常類(lèi)似。它也是一個(gè)工廠,但卻是用于主動(dòng)地連接遠(yuǎn)程主機(jī)。在連接建立后,它將自動(dòng)回調(diào)適當(dāng)?shù)姆?wù)處理對(duì)象的open()方法。連接器通常被用在你本來(lái)會(huì)使用BSD?connect()調(diào)用的地方。在ACE中,連接器,就如同接受器,被實(shí)現(xiàn)為名為ACE_Connector的模板容器類(lèi)。如先前所提到的,它需要兩個(gè)參數(shù),第一個(gè)是事件處理器類(lèi),它在連接建立時(shí)被調(diào)用;第二個(gè)是“具體的”連接器類(lèi)。

  你必須注意,底層的具體連接器和ACE_Connector工廠是非常不一樣的。ACE_Connector工廠使用底層的具體連接器來(lái)建立連接。隨后ACE_Connector工廠使用適當(dāng)?shù)氖录蚍?wù)處理例程(通過(guò)模板參數(shù)傳入)來(lái)在具體的連接器建立起連接之后處理新連接。如我們?cè)贗PC一章中看到的,沒(méi)有ACE_Connector工廠,也可以使用這個(gè)具體的連接器。但是,沒(méi)有具體的連接器類(lèi),就會(huì)無(wú)法使用ACE_Connector工廠(因?yàn)橐删唧w的連接器類(lèi)來(lái)實(shí)際處理連接建立)。

  下面是對(duì)ACE_Connector類(lèi)進(jìn)行實(shí)例化的一個(gè)例子:

  typedef?ACE_Connector<My_Svc_Handler,ACE_SOCK_CONNECTOR>?MyConnector;

這個(gè)例子中的第二個(gè)參數(shù)是具體連接器類(lèi)ACE_SOCK_CONNECTOR。連接器和接受器模式一樣,在內(nèi)部使用反應(yīng)堆來(lái)在連接建立后回調(diào)服務(wù)處理器的open()方法。我們可以復(fù)用我們?yōu)榍懊娴慕邮芷骼铀鶎?xiě)的服務(wù)處理例程。

7.3?高級(jí)課程

  下面的部分更為詳細(xì)地解釋接受器和連接器模式實(shí)際上是如何工作的。如果你想要調(diào)諧服務(wù)處理和連接建立策略(其中包括調(diào)諧底層具體連接器將要使用的服務(wù)處理例程的創(chuàng)建和并發(fā)策略,以及連接建立策略),對(duì)該模式的進(jìn)一步了解就是必要的。此外,還有一部分內(nèi)容解釋怎樣使用通過(guò)ACE_Svc_Handler類(lèi)自動(dòng)獲得的高級(jí)特性。最后,我們說(shuō)明怎樣與接受器和連接器模式一起使用簡(jiǎn)單的輕量級(jí)ACE_Event_Handler。

7.3.1?ACE_SVC_HANDLER類(lèi)

  如上面所提到的,ACE_Svc_Handler類(lèi)基于ACE_Task(它是ASX流構(gòu)架的一部分)和ACE_Event_Handler接口類(lèi)。因而ACE_Svc_Handler既是任務(wù),又是事件處理器。這里我們將簡(jiǎn)要介紹ACE_Task和ACE_Svc_Handler的功能。

7.3.1.1?ACE_Task

  ACE_Task被設(shè)計(jì)為與ASX流構(gòu)架一起使用;ASX基于UNIX系統(tǒng)V中的流機(jī)制。在設(shè)計(jì)上ASX與Larry?Peterson構(gòu)建的X-kernel協(xié)議工具非常類(lèi)似。

  ASX的基本概念是:到來(lái)的消息會(huì)被分配給由若干模塊(module)組成的流。每個(gè)模塊在到來(lái)的消息上執(zhí)行某種固定操作,然后把它傳遞給下一個(gè)模塊作進(jìn)一步處理,直到它到達(dá)流的末端為止。模塊中的實(shí)際處理由任務(wù)來(lái)完成。每個(gè)模塊通常有兩個(gè)任務(wù),一個(gè)用于處理到來(lái)的消息,一個(gè)用于處理外出的消息。在構(gòu)造協(xié)議棧時(shí),這種結(jié)構(gòu)是非常有用的。因?yàn)槊總€(gè)模塊都有固定的簡(jiǎn)單接口,所創(chuàng)建的模塊可以很容易地在不同的應(yīng)用間復(fù)用。例如,設(shè)想一個(gè)應(yīng)用,它處理來(lái)自數(shù)據(jù)鏈路層的消息。程序員會(huì)構(gòu)造若干模塊,每個(gè)模塊分別處理不同層次的協(xié)議。因而,他會(huì)構(gòu)造一個(gè)單獨(dú)的模塊,進(jìn)行網(wǎng)絡(luò)層處理;另一個(gè)進(jìn)行傳輸層處理;還有一個(gè)進(jìn)行表示層處理。在構(gòu)造這些模塊之后,它們可以(在ASX的幫助下)被“串”成一個(gè)流來(lái)使用。如果后來(lái)創(chuàng)建了一個(gè)新的(也許是更好的)傳輸模塊,就可以在不對(duì)程序產(chǎn)生任何影響的情況下、在流中替換先前的傳輸模塊。注意模塊就像是容納任務(wù)的容器。這些任務(wù)是實(shí)際的處理元件。一個(gè)模塊可能需要兩個(gè)任務(wù),如同在上面的例子中;也可能只需要一個(gè)任務(wù)。如你可能會(huì)猜到的,ACE_Task是模塊中被稱(chēng)為任務(wù)的處理元件的實(shí)現(xiàn)。

7.3.1.2任務(wù)通信的體系結(jié)構(gòu)

  每個(gè)ACE_Task都有一個(gè)內(nèi)部的消息隊(duì)列,用以與其他任務(wù)、模塊或是外部世界通信。如果一個(gè)ACE_Task想要發(fā)送一條消息給另一個(gè)任務(wù),它就將此消息放入目的任務(wù)的消息隊(duì)列中。一旦目的任務(wù)收到此消息,它就會(huì)立即對(duì)它進(jìn)行處理。

所有ACE_Task都可以作為0個(gè)或多個(gè)線程來(lái)運(yùn)行。消息可以由多個(gè)線程放入ACE_Task的消息隊(duì)列,或是從中取出,程序員無(wú)需擔(dān)心破壞任何數(shù)據(jù)結(jié)構(gòu)。因而任務(wù)可被用作由多個(gè)協(xié)作線程組成的系統(tǒng)的基礎(chǔ)構(gòu)建組件。各個(gè)線程控制都可封裝在ACE_Task中,與其他任務(wù)通過(guò)發(fā)送消息到它們的消息隊(duì)列來(lái)進(jìn)行交互。

這種體系結(jié)構(gòu)的唯一問(wèn)題是,任務(wù)只能通過(guò)消息隊(duì)列與在同一進(jìn)程內(nèi)的其他任務(wù)相互通信。ACE_Svc_Handler解決了這一問(wèn)題,它同時(shí)繼承自ACE_Task和ACE_Event_Handler,并且增加了一個(gè)私有數(shù)據(jù)流。這種結(jié)合使得ACE_Svc_Handler對(duì)象能夠用作這樣的任務(wù)(并發(fā),同一進(jìn)程);它能夠處理事件(異步,不同進(jìn)程)、并與遠(yuǎn)地主機(jī)的任務(wù)間發(fā)送和接收數(shù)據(jù)。

ACE_Task被實(shí)現(xiàn)為模板容器,它通過(guò)鎖定機(jī)制來(lái)進(jìn)行實(shí)例化。該鎖用于保證內(nèi)部的消息隊(duì)列在多線程環(huán)境中的完整性。如先前所提到的,ACE_Svc_Handler模板容器不僅需要鎖定機(jī)制,還需要用于與遠(yuǎn)地任務(wù)通信的底層數(shù)據(jù)流來(lái)作為參數(shù)。

7.3.1.3?創(chuàng)建ACE_Svc_Handler

  ACE_Svc_Handler模板通過(guò)鎖定機(jī)制和底層流來(lái)實(shí)例化,以創(chuàng)建所需的服務(wù)處理器。如果應(yīng)用只是單線程的,就不需要使用鎖,可以用ACE_NULL_SYNCH來(lái)將其實(shí)例化。但是,如果我們想要在多線程應(yīng)用中使用這個(gè)模板,可以這樣來(lái)進(jìn)行實(shí)例化:

class?MySvcHandler:

public?ACE_Svc_Handler<ACE_SOCK_STREAM,ACE_MT_SYNCH>

{

}

7.3.1.4?在服務(wù)處理器中創(chuàng)建多個(gè)線程

  在上面的例7-5中,我們使用ACE_Thread包裝類(lèi)和它的靜態(tài)方法spawn(),創(chuàng)建了單獨(dú)的線程來(lái)發(fā)送數(shù)據(jù)給遠(yuǎn)地對(duì)端。但是,在我們完成此工作時(shí),我們必須定義使用C++?static修飾符的文件范圍內(nèi)的靜態(tài)send_data()方法。結(jié)果當(dāng)然就是,我們無(wú)法訪問(wèn)我們實(shí)例化的實(shí)際對(duì)象的任何數(shù)據(jù)成員。換句話說(shuō),我們被迫使send_data()成員函數(shù)成為class-wide的函數(shù),而這并不是我們所想要的。這樣做的唯一原因是,ACE_Thread::spawn()只能使用靜態(tài)成員函數(shù)來(lái)作為它所創(chuàng)建的線程的入口。另一個(gè)有害的副作用是到對(duì)端流的引用也必須成為靜態(tài)的。簡(jiǎn)而言之,這不是編寫(xiě)這些代碼的最好方式。

  ACE_Task提供了更好的機(jī)制來(lái)避免發(fā)生這樣的問(wèn)題。每個(gè)ACE_Task都有activate()方法,可用于為ACE_Task創(chuàng)建線程。所創(chuàng)建的線程的入口是非靜態(tài)成員函數(shù)svc()。因?yàn)閟vc()是非靜態(tài)函數(shù),它可以調(diào)用任何對(duì)象實(shí)例專(zhuān)有的數(shù)據(jù)或成員函數(shù)。ACE對(duì)程序員隱藏了該機(jī)制的所有實(shí)現(xiàn)細(xì)節(jié)。activate()方法有著非常多的用途,它允許程序員創(chuàng)建多個(gè)線程,所有這些線程都使用svc()方法作為它們的入口。還可以設(shè)置線程優(yōu)先級(jí)、句柄、名字,等等。activate()方法的原型是: 

//?=?Active?object?activation?method.

virtual?int?activate?(long?flags?=?THR_NEW_LWP,

int?n_threads?=?1,

int?force_active?=?0,

long?priority?=?ACE_DEFAULT_THREAD_PRIORITY,

int?grp_id?=?-1,

ACE_Task_Base?*task?=?0,

ACE_hthread_t?thread_handles[]?=?0,

void?*stack[]?=?0,

size_t?stack_size[]?=?0,

ACE_thread_t?thread_names[]?=?0);

  第一個(gè)參數(shù)flags描述將要?jiǎng)?chuàng)建的線程所希望具有的屬性。在線程一章里有詳細(xì)描述。可用的標(biāo)志有:

THR_CANCEL_DISABLE,?THR_CANCEL_ENABLE,?THR_CANCEL_DEFERRED,

THR_CANCEL_ASYNCHRONOUS,?THR_BOUND,?THR_NEW_LWP,?THR_DETACHED,

THR_SUSPENDED,?THR_DAEMON,?THR_JOINABLE,?THR_SCHED_FIFO,

THR_SCHED_RR,?THR_SCHED_DEFAULT

  第二個(gè)參數(shù)n_threads指定要?jiǎng)?chuàng)建的線程的數(shù)目。第三個(gè)參數(shù)force_active用于指定是否應(yīng)該創(chuàng)建新線程,即使activate()方法已在先前被調(diào)用過(guò)、因而任務(wù)或服務(wù)處理器已經(jīng)在運(yùn)行多個(gè)線程。如果此參數(shù)被設(shè)為false(0),且如果activate()是再次被調(diào)用,該方法就會(huì)設(shè)置失敗代碼,而不會(huì)生成更多的線程。

  第四個(gè)參數(shù)用于設(shè)置運(yùn)行線程的優(yōu)先級(jí)。缺省情況下,或優(yōu)先級(jí)被設(shè)為ACE_DEFAULT_THREAD_PRIORITY,方法會(huì)使用給定的調(diào)度策略(在flags中指定,例如,THR_SCHED_DEFAULT)的“適當(dāng)”優(yōu)先級(jí)。這個(gè)值是動(dòng)態(tài)計(jì)算的,并且是在給定策略的最低和最高優(yōu)先級(jí)之間。如果顯式地給定一個(gè)值,這個(gè)值就會(huì)被使用。注意實(shí)際的優(yōu)先級(jí)值極大地依賴(lài)于實(shí)現(xiàn),最好不要直接使用。在線程一章中,可讀到更多有關(guān)線程優(yōu)先級(jí)的內(nèi)容。

  還可以傳入將要?jiǎng)?chuàng)建的線程的線程句柄、線程名和棧空間,以在線程創(chuàng)建過(guò)程中使用。如果它們被設(shè)置為NULL,它們就不會(huì)被使用。但是如果要使用activate創(chuàng)建多個(gè)線程,就必須傳入線程的名字或句柄,才能有效地對(duì)它們進(jìn)行使用。

7.3.1.5使用服務(wù)處理器中的消息隊(duì)列機(jī)制

  如前面所提到的,ACE_Svc_Handler類(lèi)擁有內(nèi)建的消息隊(duì)列。這個(gè)消息隊(duì)列被用作在ACE_Svc_Handler和外部世界之間的主要通信接口。其他任務(wù)想要發(fā)給該服務(wù)處理器的消息被放入它的消息隊(duì)列中。這些消息會(huì)在單獨(dú)的線程里(通過(guò)調(diào)用activate()方法創(chuàng)建)處理。隨后另一個(gè)線程就可以把處理過(guò)的消息通過(guò)網(wǎng)絡(luò)發(fā)送給另外的遠(yuǎn)地目的地(很可能是另外的ACE_Svc_Handler)。

  如先前所提到的,在這種多線程情況下,ACE_Svc_Handler會(huì)自動(dòng)地使用鎖來(lái)確保消息隊(duì)列的完整性。所用的鎖即通過(guò)實(shí)例化ACE_Svc_Handler模板類(lèi)創(chuàng)建具體服務(wù)處理器時(shí)所傳遞的鎖。之所用通過(guò)這樣的方式來(lái)傳遞鎖,是因?yàn)檫@樣程序員就可以對(duì)他的應(yīng)用進(jìn)行“調(diào)諧”。不同平臺(tái)上的不同鎖定機(jī)制有著不同程度的開(kāi)銷(xiāo)。如果需要,程序員可以創(chuàng)建他自己的優(yōu)化的、遵從ACE的鎖接口定義的鎖,并將其用于服務(wù)處理器。這是程序員通過(guò)使用ACE可獲得的靈活性的又一范例。重要的是程序員必須意識(shí)到,在此服務(wù)處理例程中的額外線程將帶來(lái)顯著的鎖定開(kāi)銷(xiāo)。為將此開(kāi)銷(xiāo)降至最低,程序員必須仔細(xì)地設(shè)計(jì)他的程序,確保使這樣的開(kāi)銷(xiāo)最小化。特別地,上面描述的例子有可能導(dǎo)致過(guò)度的開(kāi)銷(xiāo),在大多數(shù)情況下可能并不實(shí)用。

  ACE_Task,進(jìn)而是ACE_Svc_Handler(因?yàn)榉?wù)處理器也是一種任務(wù)),具有若干可用于對(duì)底層隊(duì)列進(jìn)行設(shè)置、操作、入隊(duì)和出隊(duì)操作的方法。這里我們將只討論這些方法中的一部分。因?yàn)樵诜?wù)處理器中(通過(guò)使用msg_queue()方法)可以獲取指向消息隊(duì)列自身的指針,所以也可以直接調(diào)用底層隊(duì)列(也就是,ACE_Message_Queue)的所有公共方法。(有關(guān)消息隊(duì)列提供的所有方法的更多細(xì)節(jié),請(qǐng)參見(jiàn)后面的“消息隊(duì)列”一章。)

  如上面所提到的,服務(wù)處理器的底層消息隊(duì)列是ACE_Message_Queue的實(shí)例,它是由服務(wù)處理器自動(dòng)創(chuàng)建的。在大多數(shù)情況下,沒(méi)有必要調(diào)用ACE_Message_Queue的底層方法,因?yàn)樵贏CE_Svc_Handler類(lèi)中已對(duì)它們的大多數(shù)進(jìn)行了包裝。ACE_Message_Queue是用于使ACE_Message_Block進(jìn)隊(duì)或出隊(duì)的隊(duì)列。每個(gè)ACE_Message_Block都含有指向“引用計(jì)數(shù)”(reference-counted)的ACE_Data_Block的指針,ACE_Data_Block依次又指向存儲(chǔ)在塊中的實(shí)際數(shù)據(jù)(見(jiàn)“消息隊(duì)列”一章)。這使得ACE_Message_Block可以很容易地進(jìn)行數(shù)據(jù)共享。

  ACE_Message_Block的主要作用是進(jìn)行高效數(shù)據(jù)操作,而不帶來(lái)許多拷貝開(kāi)銷(xiāo)。每個(gè)消息塊都有一個(gè)讀指針和寫(xiě)指針。無(wú)論何時(shí)我們從塊中讀取時(shí),讀指針會(huì)在數(shù)據(jù)塊中向前增長(zhǎng)。類(lèi)似地,當(dāng)我們向塊中寫(xiě)的時(shí)候,寫(xiě)指針也會(huì)向前移動(dòng),這很像在流類(lèi)型系統(tǒng)中的情況。可以通過(guò)ACE_Message_Block的構(gòu)造器向它傳遞分配器,以用于分配內(nèi)存(有關(guān)Allocator的更多信息,參見(jiàn)“內(nèi)存管理”一章)。例如,可以使用ACE_Cached_Allocation_Strategy,它預(yù)先分配內(nèi)存并從內(nèi)存池中返回指針,而不是在需要的時(shí)候才從堆中分配內(nèi)存。這樣的功能在需要可預(yù)測(cè)的性能時(shí)十分有用,比如在實(shí)時(shí)系統(tǒng)中。

7.4?接受器和連接器模式工作原理

  接受器和連接器工廠(也就是ACE_Connector和ACE_Acceptor)有著非常類(lèi)似的運(yùn)行結(jié)構(gòu)。它們的工作可大致劃分為三個(gè)階段:

·?端點(diǎn)或連接初始化階段?

·?服務(wù)初始化階段?

·?服務(wù)處理階段?

7.4.1?端點(diǎn)或連接初始化階段

  在使用接受器的情況下,應(yīng)用級(jí)程序員可以調(diào)用ACE_Acceptor工廠的open()方法,或是它的缺省構(gòu)造器(它實(shí)際上會(huì)調(diào)用open()方法),來(lái)開(kāi)始被動(dòng)偵聽(tīng)連接。當(dāng)接受器工廠的open()方法被調(diào)用時(shí),如果反應(yīng)堆單體還沒(méi)有被實(shí)例化,open()方法就首先對(duì)其進(jìn)行實(shí)例化。隨后它調(diào)用底層具體接受器的open()方法。于是具體接受器會(huì)完成必要的初始化來(lái)偵聽(tīng)連接。例如,在使用ACE_SOCK_Acceptor的情況中,它打開(kāi)socket,將其綁定到用戶想要在其上偵聽(tīng)新連接的端口和地址上。在綁定端口后,它將會(huì)發(fā)出偵聽(tīng)調(diào)用。open方法隨后將接受器工廠登記到反應(yīng)堆。因而在接收到任何到來(lái)的連接請(qǐng)求時(shí),反應(yīng)堆會(huì)自動(dòng)回調(diào)接受器工廠的handle_input()方法。注意正是因?yàn)檫@一原因,接受器工廠才從ACE_Event_Handler類(lèi)層次派生;這樣它才可以響應(yīng)ACCEPT事件,并被反應(yīng)堆自動(dòng)回調(diào)。  

  在使用連接器的情況中,應(yīng)用程序員調(diào)用連接器工廠的connect()方法或connect_n()方法來(lái)發(fā)起到對(duì)端的連接。除了其他一些選項(xiàng),這兩個(gè)方法的參數(shù)包括我們想要連接到的遠(yuǎn)地地址,以及我們是想要同步還是異步地完成連接。我們可以同步或異步地發(fā)起NUMBER_CONN個(gè)連接:

//Synchronous

OurConnector.connect_n(NUMBER_CONN,ArrayofMySvcHandlers,Remote_Addr,0,

ACE_Synch_Options::synch);

?

//Asynchronous

OurConnector.connect_n(NUMBER_CONN,ArrayofMySvcHandlers,Remote_Addr,0,

ACE_Synch_Options::asynch);

 ??如果連接請(qǐng)求是異步的,ACE_Connector會(huì)在反應(yīng)堆上登記自己,等待連接被建立(ACE_Connector也派生自ACE_Event_Handler類(lèi)層次)。一旦連接被建立,反應(yīng)堆將隨即自動(dòng)回調(diào)連接器。但如果連接請(qǐng)求是同步的,connect()調(diào)用將會(huì)阻塞,直到連接被建立、或是超時(shí)到期為止。超時(shí)值可通過(guò)改變特定的ACE_Synch_Options來(lái)指定。詳情請(qǐng)參見(jiàn)參考手冊(cè)。

7.4.2?接受器的服務(wù)初始化階段

  在有連接請(qǐng)求在指定的地址和端口上到來(lái)時(shí),反應(yīng)堆自動(dòng)回調(diào)ACE_Acceptor工廠的handle_input()方法。

  該方法是一個(gè)“模板方法”(Template?Method)。模板方法用于定義一個(gè)算法的若干步驟的順序,并允許改變特定步驟的執(zhí)行。這種變動(dòng)是通過(guò)允許子類(lèi)定義這些方法的實(shí)現(xiàn)來(lái)完成的。(有關(guān)模板方法的更多信息見(jiàn)“設(shè)計(jì)模式”參考指南)。

  在我們的這個(gè)案例中,模板方法將算法定義如下:

·?make_svc_handler():創(chuàng)建服務(wù)處理器。?

·?accept_svc_handler():將連接接受進(jìn)前一步驟創(chuàng)建的服務(wù)處理器。?

·?activate_svc_handler():啟動(dòng)這個(gè)新服務(wù)處理器。?

  這些方法都可以被重新編寫(xiě),從而靈活地決定這些操作怎樣來(lái)實(shí)際執(zhí)行。

  這樣,handle_input()將首先調(diào)用make_svc_handler()方法,創(chuàng)建適當(dāng)類(lèi)型的服務(wù)處理器(如我們?cè)谏厦娴睦又兴吹降哪菢?#xff0c;服務(wù)處理器的類(lèi)型由應(yīng)用程序員在ACE_Acceptor模板被實(shí)例化時(shí)傳入)。在缺省情況下,make_svc_handler()方法只是實(shí)例化恰當(dāng)?shù)姆?wù)處理器。但是,make_svc_handler()是一個(gè)“橋接”(bridge)方法,可被重載以提供更多復(fù)雜功能。(橋接是一種設(shè)計(jì)模式,它使類(lèi)層次的接口與實(shí)現(xiàn)去耦合。參閱“設(shè)計(jì)模式”參考文獻(xiàn))。例如,服務(wù)處理器可創(chuàng)建為進(jìn)程級(jí)或線程級(jí)的單體,或者從庫(kù)中動(dòng)態(tài)鏈接,從磁盤(pán)中加載,甚或通過(guò)更復(fù)雜的方式創(chuàng)建,如從數(shù)據(jù)庫(kù)中查找并獲取服務(wù)處理器,并將它裝入內(nèi)存。

  在服務(wù)處理器被創(chuàng)建后,handle_input()方法調(diào)用accept_svc_handler()。該方法將連接“接受進(jìn)”服務(wù)處理器;缺省方式是調(diào)用底層具體接受器的accept()方法。在ACE_SOCK_Acceptor被用作具體接受器的情況下,它調(diào)用BSD?accept()例程來(lái)建立連接(“接受”連接)。在連接建立后,連接句柄在服務(wù)處理器中被自動(dòng)設(shè)置(接受“進(jìn)”服務(wù)處理器);這個(gè)服務(wù)處理器是先前通過(guò)調(diào)用make_svc_handler()創(chuàng)建的。該方法也可被重載,以提供更復(fù)雜的功能。例如,不是實(shí)際創(chuàng)建新連接,而是“回收利用”舊連接。在我們演示各種不同的接受和連接策略時(shí),將更為詳盡地討論這一點(diǎn)。

7.4.3?連接器的服務(wù)初始化階段

  應(yīng)用發(fā)出的connect()方法與接受器工廠中的handle_input()相類(lèi)似,也就是,它是一個(gè)“模板方法”。

  在我們的這個(gè)案例中,模板方法connect()定義下面一些可被重定義的步驟:

·?make_svc_handler():創(chuàng)建服務(wù)處理器。?

·?connect_svc_handler():將連接接受進(jìn)前一步驟創(chuàng)建的服務(wù)處理器。?

·?activate_svc_handler():啟動(dòng)這個(gè)新服務(wù)處理器。?

  每一方法都可以被重新編寫(xiě),從而靈活地決定這些操作怎樣來(lái)實(shí)際執(zhí)行。

  這樣,在應(yīng)用發(fā)出connect()調(diào)用后,連接器工廠通過(guò)調(diào)用make_svc_handler()來(lái)實(shí)例化恰當(dāng)?shù)姆?wù)處理器,一如在接受器的案例中所做的那樣。其缺省行為只是實(shí)例化適當(dāng)?shù)念?lèi),并且也可以通過(guò)與接受器完全相同的方式重載。進(jìn)行這樣的重載的原因可以與上面提到的原因非常類(lèi)似。

  在服務(wù)處理器被創(chuàng)建后,connect()調(diào)用確定連接是要成為異步的還是同步的。如果是異步的,在繼續(xù)下一步驟之前,它將自己登記到反應(yīng)堆,隨后調(diào)用connect_svc_handler()方法。該方法的缺省行為是調(diào)用底層具體連接器的connect()方法。在使用ACE_SOCK_Connector的情況下,這意味著將適當(dāng)?shù)倪x項(xiàng)設(shè)置為阻塞或非阻塞式I/O,然后發(fā)出BSD?connect()調(diào)用。如果連接被指定為同步的,connect()調(diào)用將會(huì)阻塞、直到連接完全建立。在這種情況下,在連接建立后,它將在服務(wù)處理器中設(shè)置句柄,以與它現(xiàn)在連接到的對(duì)端通信(該句柄即是通過(guò)在服務(wù)處理器中調(diào)用peer()方法獲得的在流中存儲(chǔ)的句柄,見(jiàn)上面的例子)。在服務(wù)處理器中設(shè)置句柄后,連接器模式將進(jìn)行到最后階段:服務(wù)處理。

  如果連接被指定為異步的,在向底層的具體連接器發(fā)出非阻塞式connect()調(diào)用后,對(duì)connect_svc_handler()的調(diào)用將立即返回。在使用ACE_SOCK_Connector的情況中,這意味著發(fā)出非阻塞式BSD?connect()調(diào)用。在連接稍后被實(shí)際建立時(shí),反應(yīng)堆將回調(diào)ACE_Connector工廠的handle_output()方法,該方法在通過(guò)make_svc_handler()方法創(chuàng)建的服務(wù)處理器中設(shè)置新句柄。然后工廠將進(jìn)行到下一階段:服務(wù)處理。

  與accept_svc_handler()情況一樣,connect_svc_handler()是一個(gè)“橋接”方法,可進(jìn)行重載以提供變化的功能。

7.4.4?服務(wù)處理(是不是有問(wèn)題???)

  一旦服務(wù)處理器被創(chuàng)建、連接被建立,以及句柄在服務(wù)處理器中被設(shè)置,ACE_Acceptor的handle_input()方法(或者在使用ACE_Connector的情況下,是handle_output()或connect_svc_handler())將調(diào)用activate_svc_handler()方法。該方法將隨即啟用服務(wù)處理器。其缺省行為是調(diào)用作為服務(wù)處理器的入口的open()方法。如我們?cè)谏厦娴睦又兴吹降?#xff0c;在服務(wù)處理器開(kāi)始執(zhí)行時(shí),open()方法是第一個(gè)被調(diào)用的方法。是在open()方法中,我們調(diào)用activate()方法來(lái)創(chuàng)建多個(gè)線程控制;并在反應(yīng)堆上登記服務(wù)處理器,這樣當(dāng)新的數(shù)據(jù)在連接上到達(dá)時(shí),它會(huì)被自動(dòng)回調(diào)。該方法也是一個(gè)“橋接”方法,可被重載以提供更為復(fù)雜的功能。特別地,這個(gè)重載的方法可以提供更為復(fù)雜的并發(fā)策略,比如,在另一不同的進(jìn)程中運(yùn)行服務(wù)處理器。

7.5?調(diào)諧接受器和連接器策略

  如上面所提到的,因?yàn)槭褂昧丝梢灾剌d的橋接方法,很容易對(duì)接受器和連接器進(jìn)行調(diào)諧。橋接方法允許調(diào)諧:

·?服務(wù)處理器的創(chuàng)建策略:通過(guò)重載接受器或連接器的make_svc_handler()方法來(lái)實(shí)現(xiàn)。例如,這可以意味著復(fù)用已有的服務(wù)處理器,或使用某種復(fù)雜的方法來(lái)獲取服務(wù)處理器,如上面所討論的那樣。?

·?連接策略:連接創(chuàng)建策略可通過(guò)重載connect_svc_handler()或accept_svc_handler()方法來(lái)改變。?

·?服務(wù)處理器的并發(fā)策略:服務(wù)處理器的并發(fā)策略可通過(guò)重載activate_svc_handler()方法來(lái)改變。例如,服務(wù)處理器可以在另外的進(jìn)程中創(chuàng)建。?

  如上所示,調(diào)諧是通過(guò)重載ACE_Acceptor或ACE_Connector類(lèi)的橋接方法來(lái)完成的。ACE的設(shè)計(jì)使得程序員很容易完成這樣的重載和調(diào)諧。

7.5.1?ACE_Strategy_Connector和ACE_Strategy_Acceptor類(lèi)

  為了方便上面所提到的對(duì)接受器和連接器模式的調(diào)諧方法,ACE提供了兩種特殊的“可調(diào)諧”接受器和連接器工廠,那就是ACE_Strategy_Acceptor和ACE_Strategy_Connector。它們和ACE_Acceptor與ACE_Connector非常類(lèi)似,同時(shí)還使用了“策略”模式。

  策略模式被用于使算法行為與類(lèi)的接口去耦合。其基本概念是允許一個(gè)類(lèi)(稱(chēng)為Context?Class,上下文類(lèi))的底層算法獨(dú)立于使用該類(lèi)的客戶進(jìn)行變動(dòng)。這是通過(guò)具體策略類(lèi)的幫助來(lái)完成的。具體策略類(lèi)封裝執(zhí)行操作的算法或方法。這些具體策略類(lèi)隨后被上下文類(lèi)用于執(zhí)行各種操作(上下文類(lèi)將“工作”委托給具體策略類(lèi))。因?yàn)樯舷挛念?lèi)不直接執(zhí)行任何操作,當(dāng)需要改變功能時(shí),無(wú)需對(duì)它進(jìn)行修改。對(duì)上下文類(lèi)所做的唯一修改是使用另一個(gè)具體策略類(lèi)來(lái)執(zhí)行改變了的操作。(要閱讀有關(guān)策略模式的更多信息,參見(jiàn)“設(shè)計(jì)模式”的附錄)。

  在ACE中,ACE_Strategy_Connector和ACE_Strategy_Acceptor使用若干具體策略類(lèi)來(lái)改變算法,以創(chuàng)建服務(wù)處理器,建立連接,以及為服務(wù)處理器設(shè)置并發(fā)方法。如你可能已經(jīng)猜到的一樣,ACE_Strategy_Connector和ACE_Strategy_Acceptor利用了上面提到的橋接方法所提供的可調(diào)諧性。

7.5.1.1?使用策略接受器和連接器

  在ACE中已有若干具體的策略類(lèi)可用于“調(diào)諧”策略接受器和連接器。當(dāng)類(lèi)被實(shí)例化時(shí),它們作為參數(shù)被傳入策略接受器或連接器。表7-2顯示了可用于調(diào)諧策略接受器和連接器類(lèi)的一些類(lèi)。

需要修改

具體策略類(lèi)

描述

創(chuàng)建策略

(重定義make_svc_handler())

ACE_NOOP_Creation_Strategy

這個(gè)具體策略并不實(shí)例化服務(wù)處理器,而只是一個(gè)空操作。

ACE_Singleton_Strategy

保證服務(wù)處理器被創(chuàng)建為單體。也就是,所有連接將有效地使用同一個(gè)服務(wù)處理例程。

ACE_DLL_Strategy

通過(guò)從動(dòng)態(tài)鏈接庫(kù)中動(dòng)態(tài)鏈接服務(wù)處理器來(lái)對(duì)它進(jìn)行創(chuàng)建。

連接策略

(重定義connect_svc_handler())

ACE_Cached_Connect_Strategy

檢查是否有已經(jīng)連接到特定的遠(yuǎn)地地址的服務(wù)處理器沒(méi)有在被使用。如果有這樣一個(gè)服務(wù)處理器,就對(duì)它進(jìn)行復(fù)用。

并發(fā)策略

(重定義activate_svc_handler())

ACE_NOOP_Concurrency_Strategy

一個(gè)“無(wú)為”(do-nothing)的并發(fā)策略。它甚至不調(diào)用服務(wù)處理器的open()方法。

ACE_Process_Strategy

在另外的進(jìn)程中創(chuàng)建服務(wù)處理器,并調(diào)用它的open()方法。

ACE_Reactive_Strategy

先在反應(yīng)堆上登記服務(wù)處理器,然后調(diào)用它的open()方法。

ACE_Thread_Strategy

先調(diào)用服務(wù)處理器的open()方法,然后調(diào)用它的activate()方法,以讓另外的線程來(lái)啟動(dòng)服務(wù)處理器的svc()方法。

         表7-2?用于調(diào)諧策略接受器和連接器類(lèi)的類(lèi)

7.5.1.2?使用ACE_Cached_Connect_Strategy進(jìn)行連接緩存

  在許多應(yīng)用中,客戶會(huì)連接到服務(wù)器,然后重新連接到同一服務(wù)器若干次;每次都要建立連接,執(zhí)行某些工作,然后掛斷連接(比如像在Web客戶中所做的那樣)。不用說(shuō),這樣做是非常低效而昂貴的,因?yàn)檫B接建立和掛斷是非常昂貴的操作。在這樣的情況下,連接者可以采用一種更好的策略:“記住”老連接并保持它,直到確定客戶不會(huì)再重新建立連接為止。ACE_Cached_Connect_Strategy就提供了這樣一種緩存策略。這個(gè)策略對(duì)象被ACE_Strategy_Connector用于提供基于緩存的連接建立。如果一個(gè)連接已經(jīng)存在,ACE_Strategy_Connector將會(huì)復(fù)用它,而不是創(chuàng)建新的連接。

  當(dāng)客戶試圖重新建立連接到先前已經(jīng)連接的服務(wù)器時(shí),ACE_Cached_Connect_Strategy確保對(duì)老的連接和服務(wù)處理器進(jìn)行復(fù)用,而不是創(chuàng)建新的連接和服務(wù)處理器。因而,實(shí)際上,ACE_Cached_Connect_Strategy不僅管理連接建立策略,它還管理服務(wù)處理器創(chuàng)建策略。因?yàn)樵诖死?#xff0c;用戶不想創(chuàng)建新的服務(wù)處理器,我們將ACE_Null_Creation_Strategy傳遞給ACE_Strategy_Connector。如果連接先前沒(méi)有建立過(guò),ACE_Cached_Connect_Strategy將自動(dòng)使用內(nèi)部的創(chuàng)建策略來(lái)實(shí)例化適當(dāng)?shù)姆?wù)處理器,它是在這個(gè)模板類(lèi)被實(shí)例化時(shí)傳入的。這個(gè)策略可被設(shè)置為用戶想要使用的任何一種策略。除此而外,也可以將ACE_Cached_Connect_Strategy自己在其構(gòu)造器中使用的創(chuàng)建、并發(fā)和recycling策略傳給它。

第8章?服務(wù)配置器(Service?Configurator):用于服務(wù)動(dòng)態(tài)配置的模式

  如果服務(wù)可以被動(dòng)態(tài)地啟動(dòng)、移除、掛起和恢復(fù),那將會(huì)方便得多。這樣,服務(wù)開(kāi)發(fā)者就不必再擔(dān)心配置的服務(wù)。他所需關(guān)心的是服務(wù)如何完成工作。管理員就可以在應(yīng)用中增加或替換新服務(wù),而不用重新編譯或關(guān)閉服務(wù)進(jìn)程。

  服務(wù)配置器模式可以完成所有這些任務(wù)。它使服務(wù)的實(shí)現(xiàn)與配置去耦合。無(wú)需關(guān)閉服務(wù)器,就可以在應(yīng)用中增加新服務(wù)和移除舊服務(wù)。在大多數(shù)情況下,提供服務(wù)的服務(wù)器都被實(shí)現(xiàn)為看守(daemon)進(jìn)程。

8.1?構(gòu)架組件

  ACE中的服務(wù)配置器由以下組件組成:

·?名為ACE_Service_Object的抽象類(lèi)。應(yīng)用開(kāi)發(fā)者必須從它派生出子類(lèi),以創(chuàng)建他自己的應(yīng)用特有的具體服務(wù)對(duì)象(Service?Object)。?

·?應(yīng)用特有的具體服務(wù)對(duì)象。?

·?服務(wù)倉(cāng)庫(kù)ACE_Service_Repository。它記錄服務(wù)器所運(yùn)行的和所知道的服務(wù)。?

·?ACE_Service_Config。它是整個(gè)服務(wù)配置器框架的應(yīng)用開(kāi)發(fā)接口。?

·?服務(wù)配置文件。該文件含有所有服務(wù)對(duì)象的配置信息。其缺省的名字是svc.conf。當(dāng)你的應(yīng)用對(duì)ACE_Service_Config發(fā)出open()調(diào)用時(shí),服務(wù)配置器框架會(huì)讀取并處理你寫(xiě)在此文件中的所有配置信息,隨后相應(yīng)地配置應(yīng)用。?

  ACE_Service_Object包括了一些由框架調(diào)用的方法,用于服務(wù)要啟動(dòng)(init())、停止(fini())、掛起(suspend())或是恢復(fù)(resume())時(shí)。ACE_Service_Object派生自ACE_Shared_Object和ACE_Event_Handler。ACE_Shared_Object在應(yīng)用想要使用操作系統(tǒng)的動(dòng)態(tài)鏈接機(jī)制來(lái)進(jìn)行加載時(shí)被用作抽象基類(lèi)。ACE_Event_Handler已在對(duì)反應(yīng)堆的討論中進(jìn)行了介紹。當(dāng)開(kāi)發(fā)者想要他的類(lèi)響應(yīng)來(lái)自反應(yīng)堆的事件時(shí),他就從ACE_Event_Handler派生他的子類(lèi)。

  為什么服務(wù)對(duì)象要從ACE_Event_Handler繼承?用戶發(fā)起重配置的一種方法是生成一個(gè)信號(hào);當(dāng)這樣的信號(hào)事件發(fā)生時(shí),反應(yīng)堆被用于處理信號(hào),并向ACE_Service_Config發(fā)出重配置請(qǐng)求。除此而外,軟件的重配置也可能在某事件產(chǎn)生后發(fā)生。因而所有的服務(wù)對(duì)象都被構(gòu)造為能對(duì)事件進(jìn)行處理。

  服務(wù)配置文件有它自己的簡(jiǎn)單腳本,用于描述你想要服務(wù)怎樣啟動(dòng)和運(yùn)行。你可以定義你是想要增加新服務(wù),還是掛起、恢復(fù)或移除應(yīng)用中現(xiàn)有的服務(wù)。另外還可以給服務(wù)發(fā)送參數(shù)。服務(wù)配置器還允許進(jìn)行基于ACE的流(stream)的重配置。我們將在討論了ACE流構(gòu)架之后再來(lái)更多地討論這一點(diǎn)。

8.2?定義配置文件

  服務(wù)配置文件指定在應(yīng)用中哪些服務(wù)要被加載和啟動(dòng)。此外,你可以指定哪些服務(wù)要被停止、掛起或恢復(fù)。還可以發(fā)送參數(shù)給你的服務(wù)對(duì)象的init()方法。

8.2.1?啟動(dòng)服務(wù)

  服務(wù)可以被靜態(tài)或動(dòng)態(tài)地啟動(dòng)。如果服務(wù)要?jiǎng)討B(tài)啟動(dòng),服務(wù)配置器實(shí)際上會(huì)從共享對(duì)象庫(kù)(也就是,動(dòng)態(tài)鏈接庫(kù))中加載服務(wù)對(duì)象。為此,服務(wù)配置器需要知道哪個(gè)庫(kù)含有此對(duì)象,并且還需要知道對(duì)象在該庫(kù)中的名字。因而,在你的代碼文件中你必須通過(guò)你需要記住的名字來(lái)實(shí)例化服務(wù)對(duì)象。于是動(dòng)態(tài)服務(wù)會(huì)這樣被配置:

dynamic?service_name?type_of_service?*?location_of_shared_lib:name_of_object?“parameters”

而靜態(tài)服務(wù)這樣被初始化:

static?service_name?“parameters_send_to_service_object”

8.2.2?掛起或恢復(fù)服務(wù)

  如剛才所提到的,你在啟動(dòng)服務(wù)時(shí)分配給它一個(gè)名字。這個(gè)名字隨后被用于掛起或恢復(fù)該服務(wù)。于是要掛起服務(wù),你所要做的就是在svc.conf文件中指定:

  suspend?service_name

  這使得服務(wù)對(duì)象中的suspend()方法被調(diào)用。隨后你的服務(wù)對(duì)象就應(yīng)該掛起它自己(基于特定服務(wù)不同的“掛起”含義)。

  如果你想要恢復(fù)這個(gè)服務(wù),你所要做的就是在svc.conf文件中指定:

  resume?service_name

  這使得服務(wù)對(duì)象中的resume()方法被調(diào)用。隨后你的服務(wù)對(duì)象就應(yīng)該恢復(fù)它自己(基于特定服務(wù)不同的“恢復(fù)”含義。)

8.2.3?停止服務(wù)

  停止并移除服務(wù)(如果服務(wù)是動(dòng)態(tài)加載的)同樣是很簡(jiǎn)單的操作,可以通過(guò)在你的配置文件中指定以下指令來(lái)完成:

remove?service_name

  這使得服務(wù)配置器調(diào)用你的應(yīng)用的fini()方法。該方法應(yīng)該使此服務(wù)停止。服務(wù)配置器自己會(huì)負(fù)責(zé)將動(dòng)態(tài)對(duì)象從服務(wù)器的地址空間里解除鏈接。

8.3?編寫(xiě)服務(wù)

  為服務(wù)配置器編寫(xiě)你自己的服務(wù)相對(duì)比較簡(jiǎn)單。你可以讓這個(gè)服務(wù)做任何你想做的事情。唯一的約束是它應(yīng)該是ACE_Service_Object的子類(lèi)。所以它必須實(shí)現(xiàn)init()和fini()方法。在ACE_Service_Config被打開(kāi)(open())時(shí),它讀取配置文件(也就是svc.conf)并根據(jù)這個(gè)文件來(lái)對(duì)服務(wù)進(jìn)行初始化。一旦服務(wù)被加載,它會(huì)調(diào)用該服務(wù)對(duì)象的init()方法。類(lèi)似地,如果配置文件要求移除服務(wù),fini()方法就會(huì)被調(diào)用。這些方法負(fù)責(zé)分配和銷(xiāo)毀服務(wù)所需的任何資源,比如內(nèi)存、連接、線程等等。在svc.conf文件中指定的參數(shù)通過(guò)服務(wù)對(duì)象的init()方法來(lái)傳入。

  下面的例子演示一個(gè)派生自ACE_Task_Base的服務(wù)。ACE_Task_Base類(lèi)含有activate()方法,用于在對(duì)象里創(chuàng)建線程。(在“任務(wù)和主動(dòng)對(duì)象”一章中討論過(guò)的ACE_Task派生自ACE_Task_Base,并包括了用于通信目的的消息隊(duì)列。因?yàn)槲覀儾恍枰覀兊姆?wù)與其它任務(wù)通信,我們僅僅使用ACE_Task_Base來(lái)幫助我們完成工作。)更多詳細(xì)信息,請(qǐng)閱讀“任務(wù)和主動(dòng)對(duì)象”一章。該服務(wù)是一個(gè)“無(wú)為”(do-nothing)的服務(wù),一旦啟動(dòng),它只是周期性地廣播當(dāng)天的時(shí)間。

  相應(yīng)的實(shí)現(xiàn)如下所述:在時(shí)間服務(wù)接收到init()調(diào)用時(shí),它在任務(wù)中啟用(activate())一個(gè)線程。這將會(huì)創(chuàng)建一個(gè)新線程,其入口為svc()方法。在svc()方法中,該線程將會(huì)進(jìn)行循環(huán),直到它看到canceled_標(biāo)志被設(shè)置為止。此標(biāo)志在服務(wù)配置構(gòu)架調(diào)用fini()時(shí)設(shè)置。但是,在fini()方法返回底層的服務(wù)配置框架之前,它必須確定在底層的線程已經(jīng)終止。因?yàn)榉?wù)配置器將要實(shí)際地卸載含有TimeService的共享庫(kù),從而將TimeService對(duì)象從應(yīng)用進(jìn)程中刪除。如果在此之前線程并未終止,它將會(huì)對(duì)已經(jīng)被服務(wù)配置器“蒸發(fā)”的代碼發(fā)出調(diào)用!我們當(dāng)然不需要這個(gè)。為了確保線程在服務(wù)配置器“蒸發(fā)”TimeService對(duì)象之前終止,程序使用了條件變量。(要更多地了解怎樣使用條件變量,請(qǐng)閱讀有關(guān)線程的章節(jié))。

  下面是一個(gè)簡(jiǎn)單的、只是用于啟用時(shí)間服務(wù)的配置文件。可以去掉注釋#號(hào)來(lái)掛起、恢復(fù)和移除服務(wù)。

例8-1c

#?To?configure?different?services,?simply?uncomment?the?appropriate

#lines?in?this?file!

#resume?TimeService

#suspend?TimeService

#remove?TimeService

#set?to?dynamically?configure?the?TimeService?object?and?do?so?without

#sending?any?parameters?to?its?init?method

dynamic?TimeService?Service_Object?*?./Server:time_service?""

  最后,下面是啟動(dòng)服務(wù)配置器的代碼段。這些代碼還設(shè)置了一個(gè)信號(hào)處理器對(duì)象,用于發(fā)起重配置。該信號(hào)處理器已被設(shè)置成響應(yīng)SIGWINCH信號(hào)(在窗口發(fā)生變化時(shí)產(chǎn)生的信號(hào))。在啟動(dòng)服務(wù)配置器之后,應(yīng)用進(jìn)入一個(gè)反應(yīng)式循環(huán),等待SIGWINCH信號(hào)事件發(fā)生。一旦事件發(fā)生,就會(huì)回調(diào)事件處理器,由它調(diào)用ACE_Service_Config的reconfigure()方法。如先前所講述的,在此調(diào)用發(fā)生時(shí),服務(wù)配置器重新讀取配置文件,并處理用戶放在其中的任何新指令。例如,在動(dòng)態(tài)啟動(dòng)TimeService后,在這個(gè)例子中你可以改變svc.conf文件,只留下一個(gè)掛起命令在里面。當(dāng)配置器讀取它時(shí),它將調(diào)用TimeService的掛起方法,從而使它掛起它的底層線程。類(lèi)似地,如果稍后你又改變了svc.conf,要求恢復(fù)服務(wù),配置器就會(huì)調(diào)用TimeService::resume()方法,從而恢復(fù)先前被掛起的線程。

8.4?使用服務(wù)管理器

  ACE_Service_Manager是可用于對(duì)服務(wù)配置器進(jìn)行遠(yuǎn)程管理的服務(wù)。它目前可以接受兩種類(lèi)型的請(qǐng)求。其一,你可以向它發(fā)送“help”消息,列出當(dāng)前被加載進(jìn)應(yīng)用的所有服務(wù)。其二,你可以向服務(wù)管理器發(fā)送“reconfigure”消息,從而使得服務(wù)配置器重新配置它自己。

第9章?消息隊(duì)列(Message?Queue)

  現(xiàn)代的實(shí)時(shí)應(yīng)用通常被構(gòu)建成一組相互通信、但又相互獨(dú)立的任務(wù)。這些任務(wù)可以通過(guò)若干機(jī)制來(lái)與對(duì)方進(jìn)行通信,其中常用的一種就是消息隊(duì)列。在這一情況下,基本的通信模式是:發(fā)送者(或生產(chǎn)者)任務(wù)將消息放入消息隊(duì)列,而接收者(或消費(fèi)者)任務(wù)從此隊(duì)列中取出消息。這當(dāng)然只是消息隊(duì)列的使用方式之一。在接下來(lái)的討論中,我們將看到若干不同的使用消息隊(duì)列的例子。

  ACE中的消息隊(duì)列是仿照UNIX系統(tǒng)V的消息隊(duì)列設(shè)計(jì)的,如果你已經(jīng)熟悉系統(tǒng)V的話,就很容易掌握ACE的消息隊(duì)列的使用。在ACE中有多種不同類(lèi)型的消息隊(duì)列可用,每一種都使用不同的調(diào)度算法來(lái)進(jìn)行隊(duì)列的入隊(duì)和出隊(duì)操作。 

9.1?消息塊

  在ACE中,消息作為消息塊(Message?Block)被放入消息隊(duì)列中。消息塊包裝正被存儲(chǔ)的實(shí)際消息數(shù)據(jù),并提供若干數(shù)據(jù)插入和處理操作。每個(gè)消息塊“包含”一個(gè)頭和一個(gè)數(shù)據(jù)塊。注意在這里“包含”是在寬松的意義上使用的。消息塊可以不對(duì)與數(shù)據(jù)塊(Data?Block)或是消息頭(Message?Header)相關(guān)聯(lián)的內(nèi)存進(jìn)行管理(盡管你可以讓消息塊進(jìn)行這樣的管理)。它僅僅持有指向兩者的指針。所以包含只是邏輯上的。數(shù)據(jù)塊持有指向?qū)嶋H的數(shù)據(jù)緩沖區(qū)的指針。如圖9-1所示,這樣的設(shè)計(jì)帶來(lái)了多個(gè)消息塊之間的數(shù)據(jù)的靈活共享。注意在圖中兩個(gè)消息塊共享一個(gè)數(shù)據(jù)塊。這樣,無(wú)需帶來(lái)數(shù)據(jù)拷貝開(kāi)銷(xiāo),就可以將同一數(shù)據(jù)放入不同的隊(duì)列中。

  消息塊類(lèi)名為ACE_Message_Block,而數(shù)據(jù)塊類(lèi)名為ACE_Data_Block。ACE_Message_Block的構(gòu)造器是實(shí)際創(chuàng)建消息塊和數(shù)據(jù)塊的方便辦法。

9.1.1?構(gòu)造消息塊

  ACE_Message_Block類(lèi)包含有若干不同的構(gòu)造器。你可以使用這些構(gòu)造器來(lái)幫助你管理隱藏在消息和數(shù)據(jù)塊后面的消息數(shù)據(jù)。ACE_Message_Block類(lèi)可用于完全地隱藏ACE_Data_Block,并為你管理消息數(shù)據(jù);或者,如果你需要,你可以自己創(chuàng)建和管理數(shù)據(jù)塊及消息數(shù)據(jù)。下一部分將考查怎樣使用ACE_Message_Block來(lái)管理消息內(nèi)存和數(shù)據(jù)塊。然后我們將考查怎樣獨(dú)立地進(jìn)行這樣的管理,而不用依賴(lài)ACE_Message_Block的管理特性。

9.1.1.1?ACE_Message_Block分配和管理數(shù)據(jù)內(nèi)存

  要?jiǎng)?chuàng)建消息塊,最容易的方法是將底層數(shù)據(jù)塊的大小傳給ACE_Message_Block的構(gòu)造器,從而創(chuàng)建ACE_Data_Block,并為消息數(shù)據(jù)分配空的內(nèi)存區(qū)。在創(chuàng)建消息塊后,你可以使用rd_ptr()和wr_ptr()方法來(lái)在消息塊中插入和移除數(shù)據(jù)。讓ACE_Message_Block來(lái)為數(shù)據(jù)和數(shù)據(jù)塊創(chuàng)建內(nèi)存區(qū)的主要優(yōu)點(diǎn)是,它會(huì)為你正確地管理所有內(nèi)存,從而使你免于在將來(lái)為許多內(nèi)存泄漏而頭疼。

  ACE_Message_Block的構(gòu)造器還允許程序員指定ACE_Message_Block在內(nèi)部分配內(nèi)存時(shí)所應(yīng)使用的分配器。如果你傳入一個(gè)分配器,消息塊將用它來(lái)為數(shù)據(jù)塊和消息數(shù)據(jù)區(qū)的創(chuàng)建分配內(nèi)存。ACE_Message_Block的構(gòu)造器為:

ACE_Message_Block?(size_t?size,

ACE_Message_Type?type?=?MB_DATA,

ACE_Message_Block?*cont?=?0,

const?char?*data?=?0,

ACE_Allocator?*allocator_strategy?=?0,

ACE_Lock?*locking_strategy?=?0,

u_long?priority?=?0,

const?ACE_Time_Value?&?execution_time?=?ACE_Time_Value::zero,

const?ACE_Time_Value?&?deadline_time?=?ACE_Time_Value::max_time);

  上面的構(gòu)造器的參數(shù)為:

1.?要與消息塊相關(guān)聯(lián)的數(shù)據(jù)緩沖區(qū)的大小。注意消息塊的大小是size,但長(zhǎng)度將為0,直到wr_ptr被設(shè)置為止。這將在后面進(jìn)一步解釋。?

2.?消息的類(lèi)型。(在ACE_Message_Type枚舉中有若干類(lèi)型可用,其中包括缺省的數(shù)據(jù)消息)。?

3.?指向“片段鏈”(fragment?chain)中的下一個(gè)消息塊的指針。消息塊可以實(shí)際地鏈接在一起來(lái)形成鏈。隨后鏈可被放入消息隊(duì)列中,就好像它是單個(gè)數(shù)據(jù)塊一樣。該參數(shù)缺省為0,意味著此塊不使用鏈。?

4.?指向要存儲(chǔ)在此消息塊中的數(shù)據(jù)緩沖區(qū)的指針。如果該參數(shù)的值為零,就會(huì)創(chuàng)建緩沖區(qū)(大小由第一個(gè)參數(shù)指定),并由該消息塊進(jìn)行管理。當(dāng)消息塊被刪除時(shí),相應(yīng)的數(shù)據(jù)緩沖區(qū)也被刪除。但是,如果在此參數(shù)中指定了數(shù)據(jù)緩沖區(qū),也就是,參數(shù)不為空,當(dāng)消息塊被銷(xiāo)毀時(shí)它就不會(huì)刪除數(shù)據(jù)緩沖區(qū)。這是一個(gè)重要特性,必須牢牢記住。?

5.?用于分配數(shù)據(jù)緩存(如果需要)的allocator_strategy,在第四個(gè)參數(shù)為空時(shí)使用(如上面所解釋的)。任何ACE_Allocator的子類(lèi)都可被用作這一參數(shù)。(關(guān)于ACE_Allocator的更多信息,參見(jiàn)“內(nèi)存管理”一章)。?

6.?如果locking_strategy不為零,它就將用于保護(hù)訪問(wèn)共享狀態(tài)(例如,引用計(jì)數(shù))的代碼區(qū),以避免競(jìng)爭(zhēng)狀態(tài)。?

7.?這個(gè)參數(shù)以及后面兩個(gè)參數(shù)用于ACE中的實(shí)時(shí)消息隊(duì)列的調(diào)度,目前應(yīng)保留它們的缺省值。?

9.1.1.2?用戶分配和管理消息內(nèi)存

  如果你正在使用ACE_Message_Block,你并不一定要讓它來(lái)為你分配內(nèi)存。消息塊的構(gòu)造器允許你: 

·?創(chuàng)建并傳入你自己的指向消息數(shù)據(jù)的數(shù)據(jù)塊。?

·?傳入指向消息數(shù)據(jù)的指針,消息塊將創(chuàng)建并設(shè)置底層的數(shù)據(jù)塊。消息塊將為數(shù)據(jù)塊、而不是消息數(shù)據(jù)管理內(nèi)存。?

  下面的例子演示怎樣將指向消息數(shù)據(jù)的指針傳給消息塊,以及ACE_Message_Block怎樣創(chuàng)建和管理底層的ACE_Data_Block。

//The?data

char?data[size];

data?=?”This?is?my?data”;

?

//Create?a?message?block?to?hold?the?data

ACE_Message_Block?*mb?=?new?ACE_Message_Block?(data,?//?data?that?is?stored

//?in?the?newly?created?data

//

blocksize);?//size?of?the?block?that

//is?to?be?stored.

  該構(gòu)造器創(chuàng)建底層數(shù)據(jù)塊,并將它設(shè)置為指向傳遞給它的數(shù)據(jù)的開(kāi)頭。被創(chuàng)建的消息塊并不拷貝該數(shù)據(jù),也不假定自己擁有它的所有權(quán)。這就意味著在消息塊mb被銷(xiāo)毀時(shí),相關(guān)聯(lián)的數(shù)據(jù)緩沖區(qū)data將不會(huì)被銷(xiāo)毀。這是有意義的:消息塊沒(méi)有拷貝數(shù)據(jù),因此內(nèi)存也不是它分配的,這樣它也不應(yīng)該負(fù)責(zé)銷(xiāo)毀它。

9.1.2?在消息塊中插入和操作數(shù)據(jù)

  除了構(gòu)造器,ACE_Message_Block還提供若干方法來(lái)直接在消息塊中插入數(shù)據(jù)。另外還有一些方法可用來(lái)操作已經(jīng)在消息塊中的數(shù)據(jù)。

  每個(gè)ACE_Message_Block都有兩個(gè)底層指針:rd_ptr和wr_ptr,用于在消息塊中讀寫(xiě)數(shù)據(jù)。它們可以通過(guò)調(diào)用rd_ptr()和wr_ptr()方法來(lái)直接訪問(wèn)。rd_ptr指向下一次讀取數(shù)據(jù)的位置,而wr_ptr指向下一次寫(xiě)入數(shù)據(jù)的位置。程序員必須小心地管理這些指針,以保證它們總是指向正確的位置。在使用這些指針讀寫(xiě)數(shù)據(jù)時(shí),程序員必須自己來(lái)增加它們的值,它們不會(huì)魔法般地自動(dòng)更新。大多數(shù)內(nèi)部的消息塊方法也使用這兩個(gè)指針,從而使它們能夠在你調(diào)用消息塊方法時(shí)改變指針狀態(tài)。程序員必須保證自己了解這些指針的變化。

9.1.2.1?拷貝與復(fù)制(Copying?and?Duplicating)

  可以使用ACE_Message_Block的copy()方法來(lái)將數(shù)據(jù)拷貝進(jìn)消息塊。

int?copy(const?char?*buf,?size_t?n);

  copy方法需要兩個(gè)參數(shù),其一是指向要拷貝進(jìn)消息塊的緩沖區(qū)的指針,其二是要拷貝的數(shù)據(jù)的大小。該方法從wr_pt指向的位置開(kāi)始往前寫(xiě),直到它到達(dá)參數(shù)n所指示的數(shù)據(jù)緩沖區(qū)的末尾。copy()還會(huì)保證wr_ptr的更新,使其指向緩沖區(qū)的新末尾處。注意該方法將實(shí)際地執(zhí)行物理拷貝,因而應(yīng)該小心使用。

  base()和length()方法可以聯(lián)合使用,以將消息塊中的整個(gè)數(shù)據(jù)緩沖區(qū)拷貝出來(lái)。base()返回指向數(shù)據(jù)塊的第一個(gè)數(shù)據(jù)條目的指針,而length()返回隊(duì)中數(shù)據(jù)的總大小。將base和length相加,可以得到指向數(shù)據(jù)塊末尾的指針。合起來(lái)使用這些方法,你就可以寫(xiě)一個(gè)例程來(lái)從消息塊中取得數(shù)據(jù),并做一次外部拷貝。

  duplicate()和clone()方法用于制作消息塊的“副本”。如它的名字所暗示的,clone()方法實(shí)際地創(chuàng)建整個(gè)消息塊的新副本,包括它的數(shù)據(jù)塊和附加部分;也就是說(shuō),這是一次“深度復(fù)制”。而另一方面,duplicate()方法使用的是ACE_Message_Block的引用計(jì)數(shù)機(jī)制。它返回指向要被復(fù)制的消息塊的指針,并在內(nèi)部增加內(nèi)部引用計(jì)數(shù)。

9.1.2.2?釋放消息塊

  一旦使用完消息塊,程序員可以調(diào)用它的release()方法來(lái)釋放它。如果消息數(shù)據(jù)內(nèi)存是由該消息塊分配的,調(diào)用release()方法就也會(huì)釋放此內(nèi)存。如果消息塊是引用計(jì)數(shù)的,release()就會(huì)減少計(jì)數(shù),直到到達(dá)0為止;之后消息塊和與它相關(guān)聯(lián)的數(shù)據(jù)塊才從內(nèi)存中被移除。

9.2?ACE的消息隊(duì)列

  如先前所提到的,ACE有若干不同類(lèi)型的消息隊(duì)列,它們大體上可劃分為兩種范疇:靜態(tài)的和動(dòng)態(tài)的。靜態(tài)隊(duì)列是一種通用的消息隊(duì)列(ACE_Message_Queue),而動(dòng)態(tài)消息隊(duì)列(ACE_Dynamic_Message_Queue)是實(shí)時(shí)消息隊(duì)列。這兩種消息隊(duì)列的主要區(qū)別是:靜態(tài)隊(duì)列中的消息具有靜態(tài)的優(yōu)先級(jí),也就是,一旦優(yōu)先級(jí)被設(shè)定就不會(huì)再改變;而另一方面,在動(dòng)態(tài)消息隊(duì)列中,基于諸如執(zhí)行時(shí)間和最終期限等參數(shù),消息的優(yōu)先級(jí)可以動(dòng)態(tài)地改變。

例子由一個(gè)Qtest類(lèi)組成,它通過(guò)ACE_NULL_SYNCH鎖定來(lái)實(shí)例化缺省大小的消息隊(duì)列。鎖(互斥體和條件變量)被消息隊(duì)列用來(lái): 

·?保證由消息塊維護(hù)的引用計(jì)數(shù)的安全,防止在有多個(gè)線程訪問(wèn)時(shí)的競(jìng)爭(zhēng)狀態(tài)。?

·?“喚醒”所有因?yàn)橄㈥?duì)列空或滿而休眠的線程。?

  在此例中,因?yàn)橹挥幸粋€(gè)線程,消息隊(duì)列的模板同步參數(shù)被設(shè)置為空(ACE_NULL_SYNCH,意味著使用ACE_Null_Mutex和ACE_Null_Condition)。隨后Qtest的enq_msgs()方法被調(diào)用,它進(jìn)入循環(huán),創(chuàng)建消息、并將其放入消息隊(duì)列中。消息數(shù)據(jù)的大小作為參數(shù)傳給ACE_Message_Block的構(gòu)造器。使用該構(gòu)造器使得內(nèi)存被自動(dòng)地管理(也就是,內(nèi)存將在消息塊被刪除時(shí),即release()時(shí)被釋放)。wr_ptr隨后被獲取(使用wr_ptr()訪問(wèn)方法),且數(shù)據(jù)被拷貝進(jìn)消息塊。在此之后,wr_ptr向前增長(zhǎng)。然后使用消息隊(duì)列的enqueue_prio()方法來(lái)實(shí)際地將消息塊放入底層消息隊(duì)列中。

  在no_msgs_個(gè)消息塊被創(chuàng)建、初始化和插入消息隊(duì)列后,enq_msgs()調(diào)用deq_msgs()方法。該方法使用ACE_Message_Queue的dequeue_head()方法來(lái)使消息隊(duì)列中的每個(gè)消息出隊(duì)。在消息出隊(duì)后,就顯示它的數(shù)據(jù),然后再釋放消息。

9.3?水位標(biāo)

  水位標(biāo)用于在消息隊(duì)列中指示何時(shí)在其中的數(shù)據(jù)已過(guò)多(消息隊(duì)列到達(dá)了高水位標(biāo)),或何時(shí)在其中的數(shù)據(jù)的數(shù)量不足(消息隊(duì)列到達(dá)了低水位標(biāo))。兩種水位標(biāo)都用于流量控制。例如,low_water_mark可用于避免像TCP中的“傻窗口綜合癥”(silly?window?syndrome)那樣的情況,而high_water_mark可用于“阻止“或減緩數(shù)據(jù)的發(fā)送或生產(chǎn)。

  ACE中的消息隊(duì)列通過(guò)維護(hù)已經(jīng)入隊(duì)的總數(shù)據(jù)量的字節(jié)計(jì)數(shù)來(lái)獲得這些功能。因而,無(wú)論何時(shí)有新消息塊被放入消息隊(duì)列中,消息隊(duì)列都將先確定它的長(zhǎng)度,然后檢查是否能將此消息塊放入隊(duì)列中(也就是,確認(rèn)如果將此消息塊入隊(duì),消息隊(duì)列沒(méi)有超過(guò)它的高水位標(biāo))。如果消息隊(duì)列不能將數(shù)據(jù)入隊(duì),而它又持有一個(gè)鎖(也就是,使用了ACE_SYNC,而不是ACE_NULL_SYNCH作為消息隊(duì)列的模板參數(shù)),它就會(huì)阻塞調(diào)用者,直到有足夠的空間可用,或是入隊(duì)方法的超時(shí)(timeout)到期。如果超時(shí)已到期,或是隊(duì)列持有一個(gè)空鎖,入隊(duì)方法就會(huì)返回-1,指示無(wú)法將消息入隊(duì)。

  類(lèi)似地,當(dāng)ACE_Message_Queue的dequeue_head方法被調(diào)用時(shí),它檢查并確認(rèn)在出隊(duì)之后,剩下的數(shù)據(jù)的數(shù)量高于低水位標(biāo)。如果不是這樣,而它又持有一個(gè)鎖,它就會(huì)阻塞;否則就返回-1,指示失敗(和入隊(duì)方法的工作方式一樣)。

  分別有兩個(gè)方法可用于設(shè)置和獲取高低水位標(biāo):

//get?the?high?water?mark

size_t?high_water_mark(void)

?

//set?the?high?water?mark

void?high_water_mark(size_t?hwm);

?

//get?the?low?water_mark

size_t?low_water_mark(void)

?

//set?the?low?water_mark

void?low_water_mark(size_t?lwm)

9.4?使用消息隊(duì)列迭代器(Message?Queue?Iterator)

  和其它容器類(lèi)的常見(jiàn)情況一樣,可將前進(jìn)(forward)和后退(reverse)迭代器用于ACE中的消息隊(duì)列。這兩個(gè)迭代器名為ACE_Message_Queue_Iterator和ACE_Message_Queue_Reverse_Iterator。它們都需要一個(gè)模板參數(shù),用于在遍歷消息隊(duì)列時(shí)進(jìn)行同步。如果有多個(gè)線程使用消息隊(duì)列,該參數(shù)就應(yīng)設(shè)為ACE_SYNCH;否則,就可設(shè)為ACE_NULL_SYNCH。在迭代器對(duì)象被創(chuàng)建時(shí),必須將我們想要進(jìn)行迭代的消息隊(duì)列的引用傳給它的構(gòu)造器。

9.5?動(dòng)態(tài)或?qū)崟r(shí)消息隊(duì)列

  如上面所提到的,動(dòng)態(tài)消息隊(duì)列是其中的消息的優(yōu)先級(jí)隨時(shí)間變化的隊(duì)列。實(shí)時(shí)應(yīng)用需要這樣的行為特性,因而這樣的隊(duì)列在實(shí)時(shí)應(yīng)用中天生更為有用。

  ACE目前提供兩種動(dòng)態(tài)消息隊(duì)列:基于最終期限(deadline)的和基于松弛度(laxity)的(參見(jiàn)[IX])動(dòng)態(tài)消息隊(duì)列。基于最終期限的消息隊(duì)列通過(guò)每個(gè)消息的最終期限來(lái)設(shè)置它們的優(yōu)先級(jí)。在使用最早deadline優(yōu)先算法來(lái)調(diào)用dequeue_head()方法時(shí),隊(duì)列中有著最早的最終期限的消息塊將最先出隊(duì)。而基于松弛度的消息隊(duì)列,同時(shí)使用執(zhí)行時(shí)間和最終期限來(lái)計(jì)算松弛度,并將其用于劃分各個(gè)消息塊的優(yōu)先級(jí)。松弛度是十分有用的,因?yàn)樵诟鶕?jù)最終期限來(lái)調(diào)度時(shí),被調(diào)度的任務(wù)有可能有最早的最終期限,但同時(shí)又有相當(dāng)長(zhǎng)的執(zhí)行時(shí)間,以致于即使它被立即調(diào)度,也不能夠完成。這會(huì)消極地影響其它任務(wù),因?yàn)樗赡茏枞切┛梢哉{(diào)度的任務(wù)。松弛度把這樣的長(zhǎng)執(zhí)行時(shí)間考慮在內(nèi),并保證任務(wù)如果不能完成,就不會(huì)被調(diào)度。松弛度隊(duì)列中的調(diào)度基于最小松弛度優(yōu)先算法。

  基于松弛度的消息隊(duì)列和基于最終期限的消息隊(duì)列都實(shí)現(xiàn)為ACE_Dynamic_Message_Queue。ACE使用策略(STRATEGY)模式來(lái)為動(dòng)態(tài)隊(duì)列提供不同的調(diào)度特性。每種消息隊(duì)列使用不同的“策略”對(duì)象來(lái)動(dòng)態(tài)地設(shè)置消息隊(duì)列中消息的優(yōu)先級(jí)。每個(gè)這樣的“策略”對(duì)象都封裝了一種不同的算法來(lái)基于執(zhí)行時(shí)間、最終期限,等等,計(jì)算優(yōu)先級(jí);并且無(wú)論何時(shí)消息入隊(duì)或是出隊(duì),都會(huì)調(diào)用這些策略對(duì)象來(lái)完成前述計(jì)算工作。(有關(guān)策略模式的更多信息,請(qǐng)參見(jiàn)“設(shè)計(jì)模式”)。消息策略模式派生自ACE_Dynamic_Message_Strategy,目前有兩種策略可用:ACE_Laxity_Message_Strategy和ACE_Deadline_Message_Strategy。因此,要?jiǎng)?chuàng)建基于松弛度的動(dòng)態(tài)消息隊(duì)列,首先必須創(chuàng)建ACE_Laxity_Message_Strategy對(duì)象。隨后,應(yīng)該對(duì)ACE_Dynamic_Message_Queue對(duì)象進(jìn)行實(shí)例化,并將新創(chuàng)建的策略對(duì)象作為參數(shù)之一傳給它的構(gòu)造器。

創(chuàng)建消息隊(duì)列

  為簡(jiǎn)化這些不同類(lèi)型的消息隊(duì)列的創(chuàng)建,ACE提供了名為ACE_Message_Queue_Factory的具體消息隊(duì)列工廠,它使用工廠方法(FACTORY?METHOD,更多信息參見(jiàn)“設(shè)計(jì)模式”)模式的一種變種來(lái)創(chuàng)建適當(dāng)類(lèi)型的消息隊(duì)列。消息隊(duì)列工廠有三個(gè)靜態(tài)的工廠方法,可用來(lái)創(chuàng)建三種不同類(lèi)型的消息隊(duì)列:

static?ACE_Message_Queue<ACE_SYNCH_USE>?*

create_static_message_queue();

?

static?ACE_Dynamic_Message_Queue<ACE_SYNCH_USE>?*

create_deadline_message_queue();

?

static?ACE_Dynamic_Message_Queue<ACE_SYNCH_USE>?*

create_laxity_message_queue();

  每個(gè)方法都返回指向剛創(chuàng)建的消息隊(duì)列的指針。注意這些方法都是靜態(tài)的,而create_static_message_queue()方法返回的是ACE_Message_Queue,其它兩個(gè)方法則返回ACE_Dynamic_Message_Queue。

能看到這里對(duì)ACE估計(jì)感興趣,下載學(xué)習(xí)ACE調(diào)試過(guò)的例程代碼

----------------------------------------------------

兄弟的公司:立即購(gòu)--手機(jī)購(gòu)物,誠(chéng)信網(wǎng)購(gòu)

歡迎轉(zhuǎn)載,請(qǐng)注明作者和出處。

轉(zhuǎn)載于:https://www.cnblogs.com/zhenjing/archive/2010/11/05/1867538.html

總結(jié)

以上是生活随笔為你收集整理的初学者:ACE学习的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。