zoukankan      html  css  js  c++  java
  • Ice笔记-利用Ice::Application类简化Ice应用

    Ice笔记-利用Ice::Application类简化Ice应用

    作者:ydogg,转载请申明。

     
    在编写Ice相关应用时,无论是Client还是Server端,都必须进行一些必要的动作,如:Ice通信器初始化、异常捕获,以及应用终止后的销毁。鉴于每个应用都需要,Ice运行时库提供了Ice::Application类来解放用户,避免重复劳动,消除繁琐的初始化和销毁细节。Ice::Application虽然实用,但总体来说是个比较简单的类,主要提供了Ice通信器初始化和信号捕获处理两大功能。下面将从功能和实现两方面进行阐述,并给出常见用法和注意事项。源码版本为Ice-3.2.1

     
    一.Ice::Application概述

    Ice::Application本身是一个抽象类,其run()函数为纯虚函数,因此必须被继承后使用。
    Ice::Application 是一个体(singleton,会个通信器。 如果你要使用多个通信器,不能使用Ice::Application来定义多个App。而至多定义一个App的实例。
    其它通信器需要使用
    Ice::initialize()手工生成。

     
    二.Ice::Application的成员

    Ice::Application无真正成员变量,其实际使用变量均在实现文件中以静态形式提供。因此其提供的主要是静态接口 

    // Application的入口函数,提供了丰富的初始化方式,一般使用第一个
    // 将应用主函数参数直接传入即可
    int main(intchar*[]);
    int main(intchar*[], const char*);
    int main(intchar*[], const Ice::InitializationData&);
    int main(intchar*[], const char*const Ice::LoggerPtr&);
    int main(const StringSeq&);
    int main(const StringSeq&const char*);
    int main(const StringSeq&const Ice::InitializationData&);

     
    // 应用的执行循环,应用需要继承这个函数并用自己的逻辑重写
    virtual int run(intchar*[]) = 0;

     
    // 信号回调函数
    // 如果需要自己对信号进行处理,则需要继承和改写这个函数
    // 注意,需在run()函数中调用callbackOnInterrupt()来向Ice表示使用用户回调
    // 该函数的默认实现是空函数
    virtual void interruptCallback(int);
     
    // 返回应用名,即argv[0]
    static const char* appName();

     
    // 返回当前使用的Ice通信器实例指针
    static CommunicatorPtr communicator();

     
    // 设置信号处理模式
    //
    // 销毁模式:信号到来时将通信器实例销毁,也是Application的默认模式
    static void destroyOnInterrupt();

    // 关闭模式:信号到来时将通信器实例关闭,但不销毁
    static void shutdownOnInterrupt();

    // 忽略模式:信号到来时将通信器不做任何处理
    static void ignoreInterrupt();

    // 用户模式:信号到来时将调用interruptCallback()函数
    static void callbackOnInterrupt();

     
    // 信号的阻止和放开,不常用
    // 阻塞信号的到来
    static void holdInterrupt();

    // 放开被阻塞的信号
    static void releaseInterrupt();

     
    // Application当前是否被信号中断
    // 可用于判断Application的结束是否由于信号造成
    static bool interrupted();

    三.使用方法

    一般直接初始化通信器的用法如下:

    #include <Ice/Ice.h>
    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的代码如下:

     


    #include <Ice/Ice.h>
    class MyApplication : virtual public Ice::Application
    {
    public:
           
    virtual int run(intchar * []) {

           
    // 如果需要,设置信号回调模式
                  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);
    }
    可以看出,繁琐的初始化细节已经不用考虑。抽象层次也更清晰一些。

    四.实现分析

    main的实现较多,但都是对函数
    int main(int, char*[], const Ice::InitializationData&)的再包装,其行为
    如下:

            建一个IceUtil::CtrlCHandler,适当地关通信器。

            保存传入的argv[0]参数。以便通appName 函数,提供用的名字。

            初始化(通过调Ice::initialize。通过用静communicator()可以访问当前使用的通信器。

            描参数向量,找与Ice run time 有关的选项,并移除这样选项。因此,在传给你的run 方法的参数向量中,不再有与Ice 有关的选项,而只有针对你的用的选项和参数。
    实际上,
    3,4步骤都由同一个函数Ice::initialize来完成。

            调用run()函数

            销毁通信器(如果正常结束,没有收到终止信号)

     
    在以上过程中,main()函数还捕获了几乎全部异常,包括IceUtil::Exception,std::exception,甚至还有const char*const string&

    函数代码如下:

    int
    Ice::Application::main(
    int argc, char* argv[], const InitializationData& initData)
    {
        
    // 不允许重复调用
        if(_communicator != 0)
        {
            cerr 
    << argv[0<< ": only one instance of the Application class can be used" << endl;
            
    return EXIT_FAILURE;
        }
        
    int status;

        
    try
        {
            
    // 设置信号捕捉器
             CtrlCHandler ctrCHandler;
            _ctrlCHandler 
    = &ctrCHandler;

            
    try
            {   
    // 内部使用的条件变量初始化,主要用于信号阻塞
                if(_condVar.get() == 0)
                {
                    _condVar.reset(
    new Cond);
                }

                
    // 初始化Ice通信器及其它变量(均为静态变量)
                _interrupted = false;
                _appName 
    = argv[0];    // 设置应用名
                    
                _application 
    = this;
                _communicator 
    = initialize(argc, argv, initData);
                _destroyed 
    = false;

                
    // 判断应用是否提供了Ice.Nohup参数
                
    // 如果Ice.Nohup大于0, Application会忽略SIGHUP(UNIX) 和 
               // 
    CTRL_LOGOFF_EVENT (Windows). 因此,如果启动应用的用户注销,
               // 设置了Ice.Nohup 的应用能继续运行(只
    适用于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的实现在IceUtil/CtrlCHandler.cpp中,其在windows下使用SetConsoleCtrlHandler()方式实现,可捕获CTRL_C_EVENTCTRL_BREAK_EVENT、CTRL_CLOSE_EVENTCTRL_LOGOFF_EVENT以及CTRL_SHUTDOWN_EVENT信号。

    linux下,通过pthread_sigmask()sigwait()配合实现,注意实现中使用了一个内部的独立线程对信号进行捕获。其选择捕获的信号有SIGHUPSIGINTSIGTERM其它Ice::Application的信号模式设置函数都是利用它来挂接自己的处理函数,来做出不同的动作。在此不再细述,请参见源码。
     

    五.参考文献
    Ice-1.3.0中文手册(马维达,感谢他的无私贡献)
    Ice-3.1.1英文手册
    Ice-3.2.1源码

  • 相关阅读:
    pyhton锁机制,进程池
    Python脚本运行出现语法错误:IndentationError:unexpected indent
    进程线程之间如何通信
    进程基础整理
    paramido简单使用教程
    python多继承简单方法
    常用模块整理-时间模块
    如何使用临时文件
    如何折分字符串技巧讨论-总结
    python中dump与dumps的区别
  • 原文地址:https://www.cnblogs.com/lidabo/p/3259017.html
Copyright © 2011-2022 走看看