《電子技術(shù)應(yīng)用》
您所在的位置:首頁 > 嵌入式技术 > 业界动态 > CAR构件远程调用中服务器端线程池模型的研究与应用

CAR构件远程调用中服务器端线程池模型的研究与应用

2008-07-02
作者:刘振国,陈榕,张爱莲

??? 摘 要: CAR構(gòu)件進(jìn)行遠(yuǎn)程調(diào)用" title="遠(yuǎn)程調(diào)用">遠(yuǎn)程調(diào)用的原理和過程,針對該過程中服務(wù)器端的效率問題提出了進(jìn)程級線程池解決辦法,構(gòu)建了進(jìn)程級線程池模型,實(shí)現(xiàn)了關(guān)鍵部分的代碼。最后結(jié)合一個簡單的構(gòu)件遠(yuǎn)程服務(wù)示例說明了其工作過程。
??? 關(guān)鍵詞: CAR構(gòu)件? 進(jìn)程級線程池? 遠(yuǎn)程調(diào)用

?

??? 20世紀(jì)80年代以來,目標(biāo)指向型軟件編程技術(shù)有了很大的發(fā)展,為大規(guī)模的軟件協(xié)同開發(fā)以及軟件標(biāo)準(zhǔn)化、軟件共享、軟件運(yùn)行安全機(jī)制等提供了理論基礎(chǔ)。其發(fā)展可以大致分為面向?qū)ο?/a>" title="面向?qū)ο?>面向?qū)ο?/a>編程、面向構(gòu)件編程、面向中間件編程三個階段。
??? CAR技術(shù)就是總結(jié)面向?qū)ο缶幊?、面向?gòu)件編程技術(shù)的發(fā)展歷史和經(jīng)驗(yàn),為更好地支持面向以Web服務(wù)為代表的下一代網(wǎng)絡(luò)應(yīng)用軟件開發(fā)而發(fā)明的。CAR為構(gòu)件軟件和應(yīng)用程序之間進(jìn)行通信提供了統(tǒng)一的標(biāo)準(zhǔn),它為構(gòu)件程序提供了一個面向?qū)ο蟮幕顒迎h(huán)境。
1 CAR構(gòu)件技術(shù)及CAR遠(yuǎn)程構(gòu)件調(diào)用的基本原理
??? CAR(Component Application Run-Time)是一個具有國內(nèi)自主知識產(chǎn)權(quán)的構(gòu)件系統(tǒng),由上海科泰世紀(jì)科技有限公司開發(fā)。CAR構(gòu)件技術(shù)定義了一套網(wǎng)絡(luò)編程時代的構(gòu)件編程模型和編程規(guī)范,它規(guī)定了一組構(gòu)件間相互調(diào)用的標(biāo)準(zhǔn),使得二進(jìn)制構(gòu)件能夠自描述及在運(yùn)行時動態(tài)鏈接。
1.1 CAR遠(yuǎn)程接口自動列集/散集技術(shù)
??? CAR是面向?qū)ο蟮能浖P停瑢ο笫撬幕疽刂?。使用對象的?yīng)用(或另一個對象)稱為客戶,有時也稱為對象的用戶。對象和客戶之間的相互作用建立在客戶/服務(wù)器模型的基礎(chǔ)上。
??? 當(dāng)
客戶端" title="客戶端">客戶端和服務(wù)器端所在地址空間不同時,客戶端的進(jìn)程要調(diào)用服務(wù)器端的構(gòu)件服務(wù),屬于遠(yuǎn)程構(gòu)件調(diào)用。CAR構(gòu)件技術(shù)支持遠(yuǎn)程接口調(diào)用,通過調(diào)用數(shù)據(jù)的列集/散集技術(shù)進(jìn)行不同地址空間的數(shù)據(jù)交互。構(gòu)件服務(wù)和構(gòu)件服務(wù)調(diào)用者可以處于操作系統(tǒng)的不同空間,而調(diào)用者可以如同在同一地址空間中使用構(gòu)件一樣透明地進(jìn)行遠(yuǎn)程接口調(diào)用,也就是說完全向用戶屏蔽了底層使用標(biāo)準(zhǔn)的列集/散集過程。
??? CAR的自動列集/散集主要用于和欣操作系統(tǒng)(Elastos),它在構(gòu)件的調(diào)用過程中的地位類似于COM的自動列集/散集。用戶如果采用默認(rèn)的列集/散集過程,則使用一個遠(yuǎn)程接口如同使用一個本地接口一樣,完全屏蔽了數(shù)據(jù)的交換、傳遞過程。
??? Elastos2.0以存根/代理機(jī)制來實(shí)現(xiàn)遠(yuǎn)程接口自動列集/散集,主要涉及到三個對象,即處于客戶端的代理(Proxy)對象,處于服務(wù)端的存根(stub)對象,以及處于內(nèi)核的(Object)對象。
??? 一個客戶端進(jìn)程不一定只調(diào)用一個遠(yuǎn)程構(gòu)件服務(wù)。為了更方便有效地與各個遠(yuǎn)程構(gòu)件交互數(shù)據(jù),Elastos在客戶端為每一個對應(yīng)的遠(yuǎn)程服務(wù)建立一個代理對象,記錄客戶進(jìn)程的信息、遠(yuǎn)程服務(wù)構(gòu)件對象的信息以及調(diào)用狀態(tài)等,負(fù)責(zé)客戶進(jìn)程與對應(yīng)的遠(yuǎn)程服務(wù)聯(lián)系。
??? Elastos會為每個提供遠(yuǎn)程服務(wù)的構(gòu)件對象建立一個存根對象,客戶端代理不是直接與遠(yuǎn)程提供服務(wù)的構(gòu)件對象聯(lián)系,而是與存根對象聯(lián)系,通過存根對象來調(diào)用構(gòu)件對象。
??? 內(nèi)核Object對象是聯(lián)系客戶端和服務(wù)器端的樞紐,保持了相關(guān)服務(wù)的信息以及創(chuàng)建對象代理所需要的一些信息。它的建立標(biāo)志著用戶可以通過某種方式遠(yuǎn)程獲得相關(guān)服務(wù)(服務(wù)的發(fā)布)。
??? CAR的自動列集/散集通過在程序運(yùn)行過程中動態(tài)生成存根/代理實(shí)現(xiàn)。一個用戶的遠(yuǎn)程構(gòu)件調(diào)用首先通過代理對象轉(zhuǎn)發(fā)到內(nèi)核相應(yīng)的Object對象,Object對象尋找到相應(yīng)的服務(wù)進(jìn)程以及存根對象,啟動某一個服務(wù)線程并將調(diào)用轉(zhuǎn)發(fā)給存根對象,然后再由存根對象去完成調(diào)用構(gòu)件方法的過程。而調(diào)用返回的過程正好與這個流程相反。圖1是對象流程調(diào)用的一個簡單示意圖。

1.2 客戶端調(diào)用遠(yuǎn)程服務(wù)步驟
??? 當(dāng)確定代理、存根都存在,并且從客戶端到服務(wù)器端建立一條可以相互通信的通路后,客戶端就可以開始遠(yuǎn)程調(diào)用了。其流程如下:
??? (1)客戶端用戶的一次CAR遠(yuǎn)程調(diào)用會轉(zhuǎn)發(fā)到代理對象上,代理對象將調(diào)用棧中的數(shù)據(jù)根據(jù)元數(shù)據(jù)" title="元數(shù)據(jù)">元數(shù)據(jù)信息打包,并傳給內(nèi)核;
??? (2)內(nèi)核根據(jù)注冊信息找到服務(wù)及存根對象,并將打包的信息傳給存根對象;
??? (3)存根對象根據(jù)元數(shù)據(jù)將數(shù)據(jù)解包,并構(gòu)建和客戶端調(diào)用棧相應(yīng)的棧內(nèi)數(shù)據(jù),并調(diào)用真正的構(gòu)件服務(wù)接口函數(shù)" title="接口函數(shù)">接口函數(shù);
??? (4)服務(wù)構(gòu)件接口函數(shù)完成調(diào)用,并返回;
??? (5)存根對象獲取接口函數(shù)調(diào)用的參數(shù)信息及返回信息, 并將其打包,通過系統(tǒng)調(diào)用返回到內(nèi)核;
??? (6)內(nèi)核將服務(wù)器端的返回信息傳遞給客戶端,客戶端從系統(tǒng)調(diào)用返回;
??? (7)代理對象獲得返回信息,根據(jù)元數(shù)據(jù)解包并回填到用戶調(diào)用棧中。整個遠(yuǎn)程構(gòu)件方法調(diào)用過程完成。
??? 圖2是按照數(shù)據(jù)流程的形式給出的一個進(jìn)程間遠(yuǎn)程調(diào)用的全部過程。

??? 從圖2可以看出,在服務(wù)進(jìn)程內(nèi),服務(wù)最終是通過服務(wù)線程來提供的。很明顯,上述過程可能存在一個問題:一個進(jìn)程可能提供不止一種服務(wù),所以可能在服務(wù)進(jìn)程內(nèi)需要多次重復(fù)地創(chuàng)建服務(wù)線程來為客戶端服務(wù)。線程的創(chuàng)建、銷毀和調(diào)度本身是有代價的,如果一個線程的任務(wù)相對簡單,則時間和空間開銷便不容忽視;如果一個服務(wù)進(jìn)程同時對外提供多個服務(wù),這種開銷會顯著地降低服務(wù)效率,從而導(dǎo)致整個系統(tǒng)的效率降低。對于Elastos這樣的嵌入式實(shí)時操作系統(tǒng)來說,這是非常致命的。
2 進(jìn)程級線程池模型
??? 由上面的分析可以看出,問題的關(guān)鍵在于對線程資源的低效管理。對于共享資源,有一個很著名的設(shè)計模式:資源池(Resource Pool)。該模式正是為了解決資源的頻繁分配﹑釋放所造成的問題。為解決上述問題,可以采用線程池技術(shù),這里的線程池基于進(jìn)程級。
2.1 線程池技術(shù)的原理
??? 線程池采用預(yù)創(chuàng)建技術(shù),在應(yīng)用程序啟動之后,將立即創(chuàng)建一定數(shù)量的線程(N),并放入空閑隊列中。這些線程都是處于阻塞(Suspended)狀態(tài),不消耗CPU,但占用較小的內(nèi)存空間。當(dāng)任務(wù)到來后,緩沖池選擇一個空閑線程,把任務(wù)傳入此線程中運(yùn)行。當(dāng)N個線程都在處理任務(wù)時,緩沖池便自動創(chuàng)建一定數(shù)量的新線程,用于處理更多的任務(wù)。在任務(wù)執(zhí)行完畢后,線程也不退出,而是繼續(xù)保持在池中等待下一次任務(wù)。當(dāng)系統(tǒng)比較空閑時,大部分線程一直處于暫停狀態(tài),線程池自動銷毀一部分線程,回收系統(tǒng)資源。
??? 基于這種預(yù)創(chuàng)建技術(shù),線程池將線程創(chuàng)建和銷毀本身所帶來的開銷分?jǐn)偟搅烁鱾€具體任務(wù)上,執(zhí)行次數(shù)越多,每個任務(wù)所分擔(dān)到的線程本身開銷則越小。
??? 面向?qū)ο缶幊讨?,?chuàng)建和銷毀對象很費(fèi)時間,因?yàn)閯?chuàng)建一個對象要獲取內(nèi)存資源或者其他更多資源。所以提高服務(wù)程序效率的一個手段就是盡可能減少創(chuàng)建和銷毀對象的次數(shù),特別是一些耗費(fèi)大量資源的對象創(chuàng)建和銷毀。如何利用已有對象來服務(wù)是一個需要解決的關(guān)鍵問題,也是為什么要設(shè)計線程池的原因。
??? 針對線程的特點(diǎn),可將一般的線程使用過程的時間分段為:
??? T1——創(chuàng)建線程的時間
??? T2——在線程中執(zhí)行任務(wù)的時間
??? T3——線程銷毀的時間
??? 則完成一個任務(wù)所需時間T=T1+T2+T3。
對于Elastos中完成ezAPI調(diào)用的線程而言,T2所占用的時間相對于T1、T3較短,T2中包含的時間僅為一個接口函數(shù)執(zhí)行的時間??梢钥闯?,線程本身的開銷所占的比例為(T1+T3)/(T1+T2+T3)。如果線程執(zhí)行的時間很短,則這筆開銷可能占到20%-50%左右;如果任務(wù)執(zhí)行時間很頻繁,則這筆開銷將不可忽略。所以線程池在Elastos操作系統(tǒng)中的使用,理論上可以顯著改善系統(tǒng)性能。圖3是其簡單的原理圖。

??? 從圖中可以看出,線程池中的線程(池線程)同普通的線程無異,實(shí)現(xiàn)上屬于同類數(shù)據(jù)結(jié)構(gòu)。但是對于線程池中的線程,其所需資源已經(jīng)分配并初始化,池線程只用在棧中構(gòu)建好ezAPI調(diào)用的相關(guān)棧布局,就可以直接調(diào)用了。
2.2 進(jìn)程級線程池模型的實(shí)現(xiàn)
??? 在模型實(shí)現(xiàn)過程中,主要涉及三個類:進(jìn)程類、線程類、線程池類。線程池對象作為進(jìn)程數(shù)據(jù)結(jié)構(gòu)的一部分而存在,一個進(jìn)程對應(yīng)一個線程池,每個線程池中存在0~MaxThreadNum個線程。當(dāng)進(jìn)程初創(chuàng)建時,線程池中的線程數(shù)為0。
2.2.1 線程池類定義
class ThreadPool {
public:
void Initialize(CProcess*pOwner);
ECODE GetThread(Thread**ppThread,ScheduleClass*pScheduleClass,uint_t uSchedulePolicy);//獲取線程池中線程
void PutBackThread(Thread*pThread);//將執(zhí)行完任務(wù)的
//線程回收
inline Thread*FindThread(ScheduleClass*pScheduleClass,
uint_t uSchedulePolicy);//尋找適合線程
inline void SetCapacity(UINT uCapacity);//設(shè)置線程池容量
~ThreadPool( );
private:
ECODE CreateThread(Thread**ppThread,ScheduleClass?鄢pScheduleClass,uint_t uSchedulePolicy);//在線程池中創(chuàng)建
//新線程
void DestroyThread(Thread*pThread);
public:
CProcess* m_pOwner;//線程池所在的進(jìn)程對象
UINT??m_uCapacity;//線程池容量
DLinkNode?m_threadList;//線程池中的空閑線程隊列
UINT??m_cThreads;//線程池中的空閑線程數(shù)量
KMutex??m_threadLock;//線程池互斥變量,用于同步
};
2.2.2 進(jìn)程類中有關(guān)線程池的代碼
class CProcess:
{
public:
CARAPI_(ULONG) AddRef(void);
CARAPI_(ULONG) Release(void);
CARAPI Start(/*[in]*/ WString wsName, /*[in]*/ WString wsArgs);
CARAPI Kill( );
public:
ThreadPool?m_threadPool;//每個進(jìn)程均有一個線程池
ProcessHContext m_hcontext;
};
2.2.3 進(jìn)程類與線程類中關(guān)于線程池操作部分的代碼
INLINE ECODE CProcess∷GetThread(Thread**ppThread)
//獲得線程
{
if(ProcessState_Finished==m_processState && this !=∷GetCurrentProcess()) {
??return E_PROCESS_ALREADY_EXITED;
}
return m_threadPool.GetThread(ppThread,pScheduleClass,uSchedulePolicy);
}
ULONG Thread∷Release(void)?//銷毀線程
{
if (ThreadState_Running!=m_uPoolThreadState) {
??if (1==lRef && !this->IsFinished() && m_pOwner)
???m_pOwner->m_threadPool.PutBackThread(this);
??else if (0==lRef) {
???m_pOwner->m_threadPool.m_threadLock.Lock();
???m_inProcLink.Detach();
???m_pOwner->m_threadPool.m_threadLock.Unlock();
??}
??delete this;
}
else assert(0 !=lRef);
return (ULONG)lRef;
}
??? 使用上面描述的線程池模型后,進(jìn)程間遠(yuǎn)程調(diào)用的過程就發(fā)生了變化,內(nèi)核空間部分的步驟7由原來的在服務(wù)進(jìn)程中直接創(chuàng)建新的線程變成了從服務(wù)進(jìn)程的線程池中直接獲取一個空閑線程來提供服務(wù),如圖4所示。

3 線程池應(yīng)用舉例
??? 下面以一個簡單的遠(yuǎn)程調(diào)用實(shí)例說明上面所描述的線程池模型的應(yīng)用。
??? 假設(shè)現(xiàn)在有三個CAR構(gòu)件:car1.dll、car2.dll、car3.dll,分別提供構(gòu)件對象obj1、obj2、obj3,每個對象中實(shí)現(xiàn)接口函數(shù)如下:
obj1∷server1( )
{
?printf(″this is the first service!\n″);
}
obj2∷server2( )
{
??printf(″this is the second service!\n″);
}
obj3∷server3( )
{
??printf(″this is the third service!\n″);
}
現(xiàn)有一個服務(wù)進(jìn)程如下:
void main( )
{
??IObject*svr1 = new obj1( );
??IObject*svr2 = new obj2( );
??IObject*svr3 = new obj3( );
??EzRegisterService(server1,svr1);//注冊服務(wù)1
??EzRegisterService(server2,svr2);//注冊服務(wù)2
??EzRegisterService(server3,svr3);//注冊服務(wù)3
??wait( );
??EzUnregisterService(server1);//注銷服務(wù)1
??EzUnregisterService(server2);//注銷服務(wù)2
??EzUnregisterService(server3);//注銷服務(wù)3
??svr1.delete( );
??svr2.delete( );
??svr3.delete( );
??……
??return;
}
??? 該進(jìn)程通過三個構(gòu)件提供三種服務(wù),每種服務(wù)提供一個簡單的打印功能。
??? 這時有三個客戶進(jìn)程分別如下:
void main( )
{
??IObject*host1;
??EzFindService(L″server1″,&host1);
//查詢服務(wù)1
??host1->server1();//提供服務(wù)1
??……
??return;
}
void main()
{
??IObject*host2;
??EzFindService(L″server2″,&host2);//查詢服務(wù)2
??host2->server2();//提供服務(wù)2
??……
??return;
}
void main()
{
??IObject*host3;
??EzFindService(L″server3″,&host3);//查詢服務(wù)3
??host3->server3();//提供服務(wù)3
??……
??return;
}
??? 上述過程中,當(dāng)三個客戶進(jìn)程并發(fā)進(jìn)行時,服務(wù)進(jìn)程就需要為每一種服務(wù)創(chuàng)建一個服務(wù)線程以提供服務(wù),這時就會利用線程池來創(chuàng)建所用的線程。這就大大提高了服務(wù)效率,從而提高了整個系統(tǒng)的性能。
??? 線程池致力于減少線程本身的開銷對應(yīng)用所產(chǎn)生的影響,但前提是線程本身開銷與線程執(zhí)行任務(wù)相比不可忽略。如果線程本身的開銷相對于線程任務(wù)執(zhí)行開銷而言可以忽略不計,則此時線程池所帶來的好處不明顯。例如對于FTP服務(wù)器以及Telnet服務(wù)器,通常傳送文件的時間較長,開銷較大,則此時采用線程池未必是理想的方法,而可以選擇“即時創(chuàng)建,即時銷毀”的策略。
??? 在構(gòu)件遠(yuǎn)程調(diào)用過程中,服務(wù)進(jìn)程中線程池的設(shè)計與實(shí)現(xiàn)可以大大提高服務(wù)效率。本文通過簡要介紹CAR構(gòu)件遠(yuǎn)程調(diào)用的原理,引出了該過程中存在的效率問題,然后針對問題提出了進(jìn)程級線程池的模型,并給出了一個簡單的實(shí)現(xiàn),通過該線程池能夠極大地提高構(gòu)件遠(yuǎn)程調(diào)用中服務(wù)器端的服務(wù)效率。
??? 該線程池是在進(jìn)程級別實(shí)現(xiàn)的,并沒有實(shí)現(xiàn)系統(tǒng)級線程池。為了在兩種方案及典型的應(yīng)用情況下取得最好的服務(wù)性能,還應(yīng)該進(jìn)一步實(shí)現(xiàn)系統(tǒng)級線程池,并根據(jù)典型應(yīng)用制定測試用例,對兩種方案進(jìn)行效率上的比較,從而從中選取一種更優(yōu)的解決方案。
參考文獻(xiàn)
[1] KORETIDE.Elastos 2.0 Operating System Manual[M/CD].http://www.koretide.com.cn,2004/2005,6.
[2] KORETIDE.CAR′s Manual[M/CD].http://www.koretide.com.cn,2004/2005,6.
[3] BOVET D P,CESATI M.Understanding the Linux Kernel,2nd Edition[M].Sebastopol:O′Reilly,2002:22-35.
[4] BUTENHOF D R.Programming with POSIX Threads.AddisonWesley,1997.
[5] KRIEMANN R.Implementation and Usage of a Thread Pool based on POSIX Threads Max-Planck-Institute for Mathematics in the Sciences.2004-10-19
[6] CALCOTE J.Thread pools and server performance.Dr.Dobb′s Juurnal,1997,7:60-64.
[7] NICHOLS B,BUTTLAR D,F(xiàn)ARRELL J P.Pthreads Programming.O′Reilly & Associates,Sebastopol,CA,1996.

本站內(nèi)容除特別聲明的原創(chuàng)文章之外,轉(zhuǎn)載內(nèi)容只為傳遞更多信息,并不代表本網(wǎng)站贊同其觀點(diǎn)。轉(zhuǎn)載的所有的文章、圖片、音/視頻文件等資料的版權(quán)歸版權(quán)所有權(quán)人所有。本站采用的非本站原創(chuàng)文章及圖片等內(nèi)容無法一一聯(lián)系確認(rèn)版權(quán)者。如涉及作品內(nèi)容、版權(quán)和其它問題,請及時通過電子郵件或電話通知我們,以便迅速采取適當(dāng)措施,避免給雙方造成不必要的經(jīng)濟(jì)損失。聯(lián)系電話:010-82306118;郵箱:aet@chinaaet.com。