Ice笔记-利用Ice::Application类简化Ice应用
作者:ydogg,轉(zhuǎn)載請申明。
?
在編寫Ice相關(guān)應(yīng)用時,無論是Client還是Server端,都必須進行一些必要的動作,如:Ice通信器初始化、異常捕獲,以及應(yīng)用終止后的銷毀。鑒于每個應(yīng)用都需要,Ice運行時庫提供了Ice::Application類來解放用戶,避免重復(fù)勞動,消除繁瑣的初始化和銷毀細節(jié)。Ice::Application雖然實用,但總體來說是個比較簡單的類,主要提供了Ice通信器初始化和信號捕獲處理兩大功能。下面將從功能和實現(xiàn)兩方面進行闡述,并給出常見用法和注意事項。源碼版本為Ice-3.2.1。
?
一.Ice::Application概述
Ice::Application本身是一個抽象類,其run()函數(shù)為純虛函數(shù),因此必須被繼承后使用。
Ice::Application?是一個單體(singleton)類,會創(chuàng)建單個通信器。?如果你要使用多個通信器,不能使用Ice::Application來定義多個App。而至多定義一個App的實例。
其它通信器需要使用Ice::initialize()手工生成。
?
二.Ice::Application的成員
Ice::Application無真正成員變量,其實際使用變量均在實現(xiàn)文件中以靜態(tài)形式提供。因此其提供的主要是靜態(tài)接口?
//?將應(yīng)用主函數(shù)參數(shù)直接傳入即可
int?main(int,?char*[]);
int?main(int,?char*[],?const?char*);
int?main(int,?char*[],?const?Ice::InitializationData&);
int?main(int,?char*[],?const?char*,?const?Ice::LoggerPtr&);
int?main(const?StringSeq&);
int?main(const?StringSeq&,?const?char*);
int?main(const?StringSeq&,?const?Ice::InitializationData&);
?//?應(yīng)用的執(zhí)行循環(huán),應(yīng)用需要繼承這個函數(shù)并用自己的邏輯重寫
virtual?int?run(int,?char*[])?=?0;
?//?信號回調(diào)函數(shù)
//?如果需要自己對信號進行處理,則需要繼承和改寫這個函數(shù)
//?注意,需在run()函數(shù)中調(diào)用callbackOnInterrupt()來向Ice表示使用用戶回調(diào)
//?該函數(shù)的默認實現(xiàn)是空函數(shù)
virtual?void?interruptCallback(int);
?
//?返回應(yīng)用名,即argv[0]
static?const?char*?appName();
?//?返回當前使用的Ice通信器實例指針
static?CommunicatorPtr?communicator();
?//?設(shè)置信號處理模式
//
//?銷毀模式:信號到來時將通信器實例銷毀,也是Application的默認模式
static?void?destroyOnInterrupt();
//?關(guān)閉模式:信號到來時將通信器實例關(guān)閉,但不銷毀
static?void?shutdownOnInterrupt();
//?忽略模式:信號到來時將通信器不做任何處理
static?void?ignoreInterrupt();
//?用戶模式:信號到來時將調(diào)用interruptCallback()函數(shù)
static?void?callbackOnInterrupt();
?//?信號的阻止和放開,不常用
//?阻塞信號的到來
static?void?holdInterrupt();
//?放開被阻塞的信號
static?void?releaseInterrupt();
?//?Application當前是否被信號中斷
//?可用于判斷Application的結(jié)束是否由于信號造成
static?bool?interrupted();
三.使用方法
一般直接初始化通信器的用法如下:
int?main(int?argc,?char?*?argv[])
{
???????int?status?=?0;
???????Ice::CommunicatorPtr?ic;
???????try?{
??????????????ic?=?Ice::initialize(argc,?argv);
??????????????//?Server?code?here...
??????????????//?...
????????}?catch?(const?Ice::Exception?&?e)?{
??????????????cerr?<<?e?<<?endl;
??????????????status?=?1;
???????}
????????if?(ic)
??????????????ic->destroy();
???????return?status;
}
?
使用 Ice::Application 的代碼如下:
?
class?MyApplication?:?virtual?public?Ice::Application
{
public:
???????virtual?int?run(int,?char?*?[])?{
???????//?如果需要,設(shè)置信號回調(diào)模式
??????????????interruptCallback();
??????????????//?ignoreInterrupt();
??????????????//?Add?Server?code?here...
??????????????//?...
??????????????return?0;
???????}
?????
??????virtual?void?interruptCallback(int)?{
?????????????cout?<<?appName()?<<?“?receive?signal?”?<<?endl;
??????}
};
int?main(int?argc,?char?*?argv[])
{
???????MyApplication?app;
???????return?app.main(argc,?argv);
} 可以看出,繁瑣的初始化細節(jié)已經(jīng)不用考慮。抽象層次也更清晰一些。
四.實現(xiàn)分析
main的實現(xiàn)較多,但都是對函數(shù)
int main(int, char*[], const Ice::InitializationData&)的再包裝,其行為
如下:
①????????創(chuàng)建一個IceUtil::CtrlCHandler,適當?shù)仃P(guān)閉通信器。
②????????保存?zhèn)魅氲?/span>argv[0]參數(shù)。以便通過靜態(tài)的appName?成員函數(shù),提供應(yīng)用的名字。
③????????初始化(通過調(diào)用Ice::initialize)。通過調(diào)用靜態(tài)的communicator()成員,可以訪問當前使用的通信器。
④????????掃描參數(shù)向量,查找與Ice run time?有關(guān)的選項,并移除這樣的選項。因此,在傳給你的run?方法的參數(shù)向量中,不再有與Ice?有關(guān)的選項,而只有針對你的應(yīng)用的選項和參數(shù)。
實際上,3,4步驟都由同一個函數(shù)Ice::initialize來完成。
⑤????????調(diào)用run()函數(shù)
⑥????????銷毀通信器(如果正常結(jié)束,沒有收到終止信號)
?
在以上過程中,main()函數(shù)還捕獲了幾乎全部異常,包括IceUtil::Exception,std::exception,甚至還有const char*和const string&。
函數(shù)代碼如下:
Ice::Application::main(int?argc,?char*?argv[],?const?InitializationData&?initData)
{
????//?不允許重復(fù)調(diào)用
????if(_communicator?!=?0)
????{
????????cerr?<<?argv[0]?<<?":?only?one?instance?of?the?Application?class?can?be?used"?<<?endl;
????????return?EXIT_FAILURE;
????}
????int?status;
????try
????{
????????//?設(shè)置信號捕捉器
?????????CtrlCHandler?ctrCHandler;
????????_ctrlCHandler?=?&ctrCHandler;
????????try
????????{???//?內(nèi)部使用的條件變量初始化,主要用于信號阻塞
????????????if(_condVar.get()?==?0)
????????????{
????????????????_condVar.reset(new?Cond);
????????????}
????????????//?初始化Ice通信器及其它變量(均為靜態(tài)變量)
????????????_interrupted?=?false;
????????????_appName?=?argv[0];????//?設(shè)置應(yīng)用名
????????????????
????????????_application?=?this;
????????????_communicator?=?initialize(argc,?argv,?initData);
????????????_destroyed?=?false;
????????????//?判斷應(yīng)用是否提供了Ice.Nohup參數(shù)
????????? ??//?如果Ice.Nohup大于0,?Application會忽略SIGHUP(UNIX)?和?
?????????? //?CTRL_LOGOFF_EVENT?(Windows).?因此,如果啟動應(yīng)用的用戶注銷,
?????????? // 設(shè)置了Ice.Nohup?的應(yīng)用能繼續(xù)運行(只適用于C++)。
?????????????_nohup?=?(_communicator->getProperties()->getPropertyAsInt("Ice.Nohup")?>?0);
????????
????????????//?收到信號的默認處理方式是銷毀通信器
????????????destroyOnInterrupt();
????????????status?=?run(argc,?argv);
????????}
????????catch(const?IceUtil::Exception&?ex)
????????{
????????????cerr?<<?_appName?<<?":?"?<<?ex?<<?endl;
????????????status?=?EXIT_FAILURE;
????????}
????????catch(const?std::exception&?ex)
????????{
????????????cerr?<<?_appName?<<?":?std::exception:?"?<<?ex.what()?<<?endl;
????????????status?=?EXIT_FAILURE;
????????}
????????catch(const?std::string&?msg)
????????{
????????????cerr?<<?_appName?<<?":?"?<<?msg?<<?endl;
????????????status?=?EXIT_FAILURE;
????????}
????????catch(const?char*?msg)
????????{
????????????cerr?<<?_appName?<<?":?"?<<?msg?<<?endl;
????????????status?=?EXIT_FAILURE;
????????}
????????catch(...)
????????{
????????????cerr?<<?_appName?<<?":?unknown?exception"?<<?endl;
????????????status?=?EXIT_FAILURE;
????????}
????????//?Application清理時,需要忽略所有信號
???????ignoreInterrupt();
????????{
????????????StaticMutex::Lock?lock(_mutex);
????????????while(_callbackInProgress)
????????????{
????????????????_condVar->wait(lock);
????????????}
????????????if(_destroyed)
????????????{
????????????????_communicator?=?0;
????????????}
????????????else
????????????{
????????????????_destroyed?=?true;
????????????????//
????????????????//?And?_communicator?!=?0,?meaning?will?be?destroyed
????????????????//?next,?_destroyed?=?true?also?ensures?that?any
????????????????//?remaining?callback?won't?do?anything
????????????????//
????????????}
????????????_application?=?0;
????????}
?? ? ??//?清理通信器(如果沒有通過信號清理過)
????????if(_communicator?!=?0)
????????{??
????????????try
????????????{
????????????????_communicator->destroy();
????????????}
????????????catch(const?IceUtil::Exception&?ex)
????????????{
????????????????cerr?<<?_appName?<<?":?"?<<?ex?<<?endl;
????????????????status?=?EXIT_FAILURE;
????????????}
????????????catch(const?std::exception&?ex)
????????????{
????????????????cerr?<<?_appName?<<?":?std::exception:?"?<<?ex.what()?<<?endl;
????????????????status?=?EXIT_FAILURE;
????????????}
????????????catch(...)
????????????{
????????????????cerr?<<?_appName?<<?":?unknown?exception"?<<?endl;
????????????????status?=?EXIT_FAILURE;
????????????}
????????????_communicator?=?0;
????????}
????????//
????????//?Set?_ctrlCHandler?to?0?only?once?communicator->destroy()?has?completed.
????????//?
????????_ctrlCHandler?=?0;
????}
????catch(const?CtrlCHandlerException&)
????{
????????cerr?<<?argv[0]?<<?":?only?one?instance?of?the?Application?class?can?be?used"?<<?endl;
????????status?=?EXIT_FAILURE;
????}
???
????return?status;
}
IceUtil::CtrlCHandler的實現(xiàn)在IceUtil/CtrlCHandler.cpp中,其在windows下使用SetConsoleCtrlHandler()方式實現(xiàn),可捕獲CTRL_C_EVENT、CTRL_BREAK_EVENT、CTRL_CLOSE_EVENT、CTRL_LOGOFF_EVENT以及CTRL_SHUTDOWN_EVENT信號。
在linux下,通過pthread_sigmask()和sigwait()配合實現(xiàn),注意實現(xiàn)中使用了一個內(nèi)部的獨立線程對信號進行捕獲。其選擇捕獲的信號有SIGHUP、SIGINT、SIGTERM。其它Ice::Application的信號模式設(shè)置函數(shù)都是利用它來掛接自己的處理函數(shù),來做出不同的動作。在此不再細述,請參見源碼。
?
五.參考文獻
Ice-1.3.0中文手冊(馬維達,感謝他的無私貢獻)
Ice-3.1.1英文手冊
Ice-3.2.1源碼
總結(jié)
以上是生活随笔為你收集整理的Ice笔记-利用Ice::Application类简化Ice应用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数据中心加速,一文说清FPGA与GPU、
- 下一篇: Ice笔记--C++线程与并发(小结)