




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、ICE系列培训(二)黄亮统一网管平台专项培训内容ICE中的异步程序设计方法(AMD,AMI)1.AMI:Asynchronous Method Invocation异步方法调用2.AMD:Asynchronous Method Dispatch异步方法派发1. 概述1.1 同步模型与异步模型区别1.2 AMI概述1.3 AMD概述1.4 元数据(metadata)与AMI,AMD1.1 同步模型与异步模型区别两者的区别:同步模型中发出调用的线程会阻塞到操作返回。异步模型则正好相反,发出调用的线程不会阻塞的等待调用结果的返回。Ice 在本质上是一个异步的中间件平台,出于对应用 (及其程序员)的考
2、虑而模拟了同步的行为。当 Ice 应用通过代理、向远地对象发出同步的双向调用时,发出调用的线程会阻塞起来,以模拟同步的方法调用。在此期间, Ice run time在后台运行,处理消息,直到收到所需的答复为止,然后发出调用的线程就可以解除阻塞并解编结果。1.2 AMI概述AMI:异步方法调用这个术语描述的是客户端的异步编程模型支持。使用 AMI发出远地调用,在 Ice run time 等待答复的同时,发出调用的线程不会阻塞。相反,发出调用的线程可以继续进行各种活动,当答复最终到达时, Ice run time会通知应用。通过回调发给应用对象通知1.3 AMD概述AMD:使用 AMD 时,服务
3、器可以接收一个请求,然后挂起其处理,以尽快释放分派线程。当处理恢复、结果已得出时,服务器要使用 Ice run time 提供的回调对象,显式地发送响应。AMD 操作通常会把请求数据 (也就是,回调对象和操作参数)放入队列 ,供应用的某个线程 (或线程池)随后处理用。这样,服务器就使分派线程的使用率降到了最低限度,能够高效地支持数千并发客户。1.3 AMD概述为什么要使用AMD:(1)默认情况下:一个服务器在同一时刻所能支持的同步请求数受到 Ice run time的服务器线程池的尺寸限制 。如果所有线程都在忙于分派长时间运行的操作,那么就没有线程可用于处理新的请求,客户就会体验到不可接受的无
4、响应状态。(2)Ice run time的服务器线程池尺寸受限于主机的CPU数。1.4 元数据与AMI,AMD1)ICE自3.4以后,提供了一套全新的AMI(异步调用方式)的API,新的API已不需要在slice文件中标记“ami”这样的元数据。2)ICE提供向下兼容性,支持“ami”的语言标记,但已标注为deprecated.3) 服务端使用AMD异步派发方式编程,仍然必须在slice文件中,对slice定义标注“amd”元数据。Tips:给客户提供某个调用方法的同步和异步版本是有益的,但如果在服务器中这样做,程序员就必须实现两种版本的分派方法,并不能带来切实的好处,而且还会带来若干潜在的缺
5、陷。1.4 元数据与AMI,AMDAMD元数据标记方式:1)接口级(interface)amd interface I bool isValid(); float computeRate();2) 操作级(operation)interface J amd void startProcess(); int endProcess();1.4 元数据与AMI,AMDAMD元数据的标记方式Tips:在操作层面、而不是接口或类的层面指定元数据,不仅能使所生成的代码的数量降到最低限度,而且,更重要的是,它还能使复杂度降到最低限度。尽管异步模型更为灵活,它的使用也更复杂。因此,最好只把它用于那些能从中获得
6、某种好处的操作;对其他操作则使用更简单的同步模型。2. AMI编程2.1 基本API2.2 AsynResult类2.3 轮询方式的完成通知(Polling for Completion)2.4 通用的完成通知回调函数(Generic Completion Callbacks)2.5 类型安全的回调(Type-Safe Completion Callbacks)2.6 单路调用(Oneway Invocations)2.7 流量控制(Flow Control)2.8 批量请求(Batch Requests)2.9 并发(Concurrency)2.10 限制(Limitations)2.11
7、示例 2.1 Slice介绍(1)Slice是什么Slice(Specification Language for Ice)是分离对象接口和实现的重要抽象机制。Slice建立了客户和服务器之间的契约,这些契约描述了应用所需的类型及对象接口。这些描述是中立与语言的,所以客户端和服务端可以使用不同的实现语言。Slice提供编译工具将Slice定义编译为具体语言的实现代码,即客户端的Proxy code和服务端的Skeleton,这样用户只用把注意力放在业务逻辑的处理上。2.1 Basic Asynchronous API1.异步方法通知(AMI)APIICE从3.4开始采用新的AMI API:mo
8、dule Demo interface Employees string getName(int number); ;1)不必再显式的注明“ami”元数据,slice工具会自动的生产同步调用与异步调用的stub代码。Ice:AsyncResultPtr begin_getName(Ice:Int number);Ice:AsyncResultPtr begin_getName(Ice:Int number, const Ice:Context& _ctx);std:string end_getName(const Ice:AsyncResultPtr&);2.1 Basic A
9、synchronous API(2)begin_xxxMethod负责向队列中插入一个调用的请求,当请求插入到队列后,便可立即返回,不必阻塞的等待调用完成。(3)end_xxxMethod负责收集异步调用的结果。当异步调用的结果还未处理完成时,调用end_xxxMethod方法会阻塞到异步调用完成处理结果。换句话说,如果结果已完成,调用end_xxxMethod方法会立即返回。示例:EmployeesPrx e = .;Ice:AsyncResultPtr r = e-begin_getName(99);/ Continue to do other things here.string nam
10、e = e-end_getName(r);Tips:AsyncResultPtr是AsynResult的智能指针,存储了ICE运行时对于异步调用的状态追踪的信息。在调用begin_xxxMethod方法相关的end_xxxMethod方法时,必须传入相应的AsyncResultPtr对象2.1 Basic Asynchronous API(4)异步方法调用中的参数Slice定义的方法参数在AMI的begin_,end_方法中有相应的变化:double op(int inp1, string inp2, out bool outp1, out long outp2);AMI:Ice:AsyncR
11、esultPtr begin_op(Ice:Int inp1,const :std:string& inp2)Ice:Double end_op(bool& outp1, Ice:Long& outp2,const Ice:AsyncResultPtr&);注意:1)slice定义中的输入参数转移为begin_op中的唯一输入参数。2)slice定义中的输出参数作为end_op的输出参数,end_op的返回值为原slice定义的返回值。3)Begin_op返回AsyncResultPtr作为end_op的输入参数。2.1 Basic Asynchronous A
12、PI(5)异常处理(Exception Handling)1)通常情况下,当异步调用过程中发生异常,在end_xxxMethod中抛出,即使异常发生在begin_xxxMethod中。2)但有2种例外的情况:当销毁了当前的Communicator后,再调用异步方法,会抛出CommunicatorDestroyedException异常。当调用方式出错时,抛出IceUtil:IllegalArgumentException异常(begin_,end_配对错误,调用的方法参数错误)2.2AsynResult类(1)AsynResult类声明class AsyncResult : virtual p
13、ublic IceUtil:Shared, private IceUtil:noncopyable public: virtual bool operator=(const AsyncResult&) const; virtual bool operator(const AsyncResult&) const; virtual Int getHash() const; virtual CommunicatorPtr getCommunicator() const; virtual ConnectionPtr getConnection() const; virtual Obje
14、ctPrx getProxy() const; const string& getOperation() const; LocalObjectPtr getCookie() const; bool isCompleted() const; void waitForCompleted(); bool isSent() const; void waitForSent(); bool sentSynchronously() const;AsyncResult类由begin_op方法返回,封装了异步调用的有关信息2.2AsynResult类(2) 方法说明 bool operator=(con
15、st AsyncResult&) const bool operatorsend(offset, bs); offset += bs.size();FileHandle file = open(.);FileTransferPrx ft = .;const int chunkSize = .;Ice:Int offset = 0;list results;const int numRequests = 5;while (!file.eof() ByteSeq bs; bs = file.read(chunkSize); / Send up to numRequests + 1 chun
16、ks asynchronously. Ice:AsyncResultPtr r = ft-begin_send(offset, bs); offset += bs.size(); / 等待请求完成发送 r-waitForSent(); results.push_back(r); /超过了水位标则阻塞等待. while (results.size() numRequests) Ice:AsyncResultPtr r = results.front(); results.pop_front(); r-waitForCompleted(); /等待剩余的请求完成.while (!results.e
17、mpty() Ice:AsyncResultPtr r = results.front(); results.pop_front(); r-waitForCompleted();2.6 完成通知1.轮询方式的完成通知1)同步方式与异步方式效率上的差距2)异步方式AsyncResult队列控制提高传输效率控制内存占用2.6 完成通知2.通用回调函数方式的完成通知相对于轮询方式的优点:解除应用逻辑与异步调用机制的耦合性。利用Ice 运行时完成客户端的异步处理逻辑。Slice提供的重载方法,红色高亮部分是回调完成通知的特征。Ice:AsyncResultPtr begin_getName( Ice:
18、Int number, const Ice:CallbackPtr& _del, const Ice:LocalObjectPtr& _cookie = 0);Ice:AsyncResultPtr begin_getName( Ice:Int number, const Ice:Context& _ctx, const Ice:CallbackPtr& _del, const Ice:LocalObjectPtr& _cookie = 0);Ice:CallbackPtr: Ice运行时提供的回调函数智能指针,存储了自定义的回调函数实例。当发生回调时,I
19、ce运行时会执行回调函数对象上绑定的方法。2.6 完成通知3.自定义的回调对象示例:class MyCallback : public IceUtil:Shared public: void finished(const Ice:AsyncResultPtr& r) EmployeesPrx e = EmployeesPrx:uncheckedCast(r-getProxy(); try string name = e-end_getName(r); cout Name is: name endl; catch (const Ice:Exception& ex) cerr Ex
20、ception is: ex endl; ;typedef IceUtil:Handle MyCallbackPtr;回调对象封装了异步调用实质的业务逻辑,异步调用本身是发出非阻塞的调用请求,但重要的是发出了请求以后,应用逻辑该如何执行。/ 应用程序AMI调用示例:EmployeesPrx e = .;MyCallbackPtr cb = new MyCallback;Ice:CallbackPtr d = Ice:newCallback(cb, &MyCallback:finished);e-begin_getName(99, d); 2.6 完成通知 4.回调对象的编写要点1)继承
21、IceUtil:Shared2) 回调对象中的回调方法,必须符合以下声明方式:void callback_method(AsyncResultPtr& r)3)回调对象中的回调方法名称可以为合乎语法的任意名称。4)回调方法中必须调用end_xxxMethod();5)回调方法必须捕获所有可能由end_xxxMethod抛出的异常,如果遗漏了某异常,Ice运行时默认会在日志中记录,但也会忽略这个异常(设置Ice.Warn.AMICallback属性为0,可以不记录日志)。2.6 完成通知5.应用程序AMI调用示例:EmployeesPrx e = .;MyCallbackPtr cb =
22、 new MyCallback;Ice:CallbackPtr d = Ice:newCallback(cb, &MyCallback:finished);e-begin_getName(99, d); 注意:1)Ice:newCallback辅助函数,将自定义的回调对象智能指针与回调方法绑定后,返回Ice:CallbackPtr类型的对象。2)begin_xxxMethod,需要输入一个Ice:CallbackPtr对象。2.6 完成通知6.回调中的CookieIce:AsyncResultPtr begin_getName( Ice:Int number, const Ice:Ca
23、llbackPtr& _del, const Ice:LocalObjectPtr& _cookie = 0);Ice:AsyncResultPtr begin_getName( Ice:Int number, const Ice:Context& _ctx, const Ice:CallbackPtr& _del, const Ice:LocalObjectPtr& _cookie = 0);Cookie对象在异步方法调用中用于begin_xxxMethod与end_xxxMethod之间传递信息。应用场景: 用户在界面上点击产生大量的异步调用,当这些
24、异步调用完成后,每个调用需要更新不同用户界面组件。在这种情景下,每个调用需要携带它所需要更新的组件信息才能完成操作。 在这种异步调用与回调函数之间需要交互的情况下,可以通过Cookie在应用中绑定相关信息。 2.6 完成通知7.Cookie的编写为了满足不同的应用场景,Cookie对象可以自定义。Cookie编写的唯一要求就是要继承Ice:LocalObject示例:class Cookie : public Ice:LocalObjectpublic: Cookie(WidgetHandle h) : _h(h) WidgetHandle getWidget() return _h; pri
25、vate: WidgetHandle _h;typedef IceUtil:Handle CookiePtr;/CookiePtr cookie1 = new Cookie(widgetHandle1);/ Make cookie for call to getName(42);CookiePtr cookie2 = new Cookie(widgetHandle2);/ Invoke the getName operation with different cookies.e-begin_getName(99, getNameCB, cookie1);e-begin_getName(24,
26、getNameCB, cookie2);voidMyCallback:getName(const Ice:AsyncResultPtr& r) EmployeesPrx e = EmployeesPrx:uncheckedCast(r-getProxy(); CookiePtr cookie = CookiePtr:dynamicCast(r-getCookie(); try string name = e-end_getName(r); cookie-getWidget()-writeString(name); catch (const Ice:Exception& ex)
27、handleException(ex); 1)在应用逻辑中创建了Cookie对象2)将Cookie对象传递给begin_getName方法3)在对应的回调方法中重新获得Cookie(需要向下转型)4)从Cookie对象中获得需要的信息2.6 完成通知8.类型安全回调函数方式的完成通知(1)通用回调方法存在一些类型安全方面的隐患在回调方法中调用end_xxxMethod前必须将代理对象向下转型为正确的代理对象类型EmployeesPrx e = EmployeesPrx:uncheckedCast(r-getProxy();调用的end_xxxMethod必须与begin_xxxMethod配对
28、如果使用了Cookie,那么也需要将Cookie向下转型为正确的Cookie类型。CookiePtr cookie = CookiePtr:dynamicCast(r-getCookie();在调用end_xxxMethod方法时,必须要捕获所有可能的异常。否则无法获知调用在何时失败Slice工具提供了一套Callback类API解决上述类型安全问题。2.6 完成通知8.类型安全回调函数方式的完成通知(2)Slice工具与类型安全的回调Slice工具在编译slice文件时,生成一系列相关的回调函数类别,在这些自动生成的代码中,将类型转换,调用end_xxxMethod等通用回调方法中的程式化方
29、法以自动生成的方式代替手工编程。(C+中是以模板的方式实现不同回调函数的模板实例)2.6 完成通知8.类型安全回调函数方式的完成通知(3)类型安全的回调函数实现要点Slice工具为slice定义的接口中的接口方法自动生成类型安全的回调类型。自定义回调类型实现具体的回调操作,处理业务逻辑。必须声明一个正常情况下处理回调的方法,该方法返回void类型,参数列表与slice定义一致。当slice返回类型不是void的时候,则第一个参数用于返回值,后续参数与slice定义中的参数列表一致。必须声明一个异常情况下,处理异常的方法(无返回值,只有一个const Ice:Exception& ex
30、输入参数)。异步方法调用下接口方法对应的类型安全的回调类型::Callback_Ptr:Callback_Ptr辅助回调函数用于将自定义的回调类型绑定到类型安全的回调类型实例上::newCallback_:newCallback_2.6 完成通知9.类型安全的回调与通用回调方式的比较1)回调方法定义不同通用回调:class MyCallback : public IceUtil:Shared public:/ 回调函数参数为const Ice:AsyncResultPtr& void finished(const Ice:AsyncResultPtr& r) ;类型安全的回调c
31、lass MyCallback : public IceUtil:Sharedpublic: void getNameCB(int number) void failureCB(const Ice:Exception& ex)void failureCB(const Ice:Exception& ex) cerr Exception is: ex begin_getName(99, d); 类型安全的回调:类型安全的回调:MyCallbackPtr cb = new MyCallback;Callback_Employees_getNamePtr getNameCB = new
32、Callback_Employees_getName( cb, &MyCallback:getNameCB, &MyCallback:failureCB);e-begin_getName(99, getNameCB);2.6 完成通知10.类型安全的Cookie调用方式MyCallbackPtr cb = new MyCallback;Callback_Employees_getNamePtr getNameCB = newCallback_Employees_getName( cb, &MyCallback:getNameCB,&MyCallback:fail
33、ureCB);CookiePtr cookie =new Cookie(widgetHandle);e-begin_getName(99, getNameCB, cookie);class MyCallback: public IceUtil:Sharedpublic: void getNameCB(const string& name, const CookiePtr& cookie) cookie-getWidget()-writeString(name);2.6 完成通知11.类型安全回调方式使用总结声明自定义回调对象实例声明类型安全的回调对象实例声明类型安全回调对象实例
34、时,利用辅助函数构造回调对象实例辅助函数中需要传递:自定义回调对象实例回调方法失败处理的回调方法2.7 单路调用1)通用的回调方式由于回调类别中回调函数具有输入参数,void callback_method(AsyncResultPtr& r)因此是双路调用,无法调用单路的代理对象方法。2)类型安全的回调方式,通过newCallback辅助方法,在回调函数对象中只指定失败的回调函数,可以调用单路方法。示例:MyCallbackPtr cb = new MyCallback;Ice:Callback_Object_ice_pingPtr callback = Ice:newCallbac
35、k_Object_ice_ping(cb,&MyCallback:failureCB);p-begin_opVoid(callback);2.8 流量控制1.流量控制的起因: 客户端并发请求非常频繁,服务端处理能力赶不上客户端发送异步请求的速度。客户端将请求发往客户端Ice运行时请求队列,队列不断增长,在不加流量控制的情况下,最终耗尽内存。 2.流量控制的功能: Ice提供了一套流量控制管理的API,应用了流量管理的api后,当客户端的请求数超过了限定的阈值,则阻塞客户端发起的新的操作请求直到队列中完成部分请求的处理,有剩余的空间容纳入队的请求。2.8 流量控制4.流量控制回调函数定义
36、1)通用回调方式void sent(const Ice:AsyncResult&);调用情景1和情景2的判断由程序员调用AsyncResult: sentSynchronously判断,自行编写逻辑。2)类型安全的回调方式void sent(bool sentSynchronously);void sent(bool sentSynchronously, const & cookie);调用情景1与情景2的判断由Ice运行时传递的sendSynchronously参数判断。2.8 流量控制3.流量控制的编程要点:流量控制的基本思想是自定义流量控制的方法。class MyCall
37、back : public IceUtil:Shared public: void finished(const Ice:AsyncResultPtr&); void sent(const Ice:AsyncResultPtr&);/ 发送请求的方法,名字可以自定义;typedef IceUtil:Handle MyCallbackPtr;情景1:当Ice运行时将请求发送到客户端的发送端上后,由调用begin_xxxMethod的方法的线程接着调用send方法。情景2:当Ice运行时将请求入队时,则由另一线程在Ice运行时将队列中请求发送到发送端后,调用send方法。以上2种情
38、况调用send的const Ice:AsyncResultPtr& 参数的sentSynchronously方法判断。在send方法中对请求数进行计数,当队列的长度达到高水位标,则阻塞,当运行时将请求发往发送端,则减少计数。2.9 批量调用1.批量调用的起因:对于大量的零散单路调用或数据包请求,服务端在处理时需要频繁的在用户态和内核态之间转换,代价非常高昂。因此引入批量调用。批量调用的细节可以参考ICE手册32.16节。2.9 批量调用2.批量调用的方法:Ice运行时提供了将客户端对象代理转换为批量调用代理的方法:/ C+namespace IceProxy namespace Ice
39、 class Object : /* . */ public: /将普通代理转换为批量调用的代理 Ice:ObjectPrx ice_batchOneway() const; Ice:ObjectPrx ice_batchDatagram() const; void ice_flushBatchRequests();/ .;2.9 批量调用3.显式调用与隐式调用 :显式同步调用:ice_flushBatchRequests显式异步调用:begin_ice_flushBatchRequestsend_ice_flushBatchRequests隐式调用:Ice.BatchAutoFlush=1(
40、默认)Ice.MessageSizeMax=1MB(默认)2.10 AMI的并发Ice运行时通常情况下由独立的线程调用异步回调方法中的回调函数。因此在回调函数中可以使用非递归锁而不怕出现死锁的情况。但如果定义了流量控制回调函数,则如前所述的规则,在不同的情景下,有不同的线程选择规则。2.11 AMI的限制采用了AMI异步回调,则不能采用collocated optimization优化。否则抛出CollocationOptimizationException。collocated optimization优化 参见ICE手册32.21节2.12 示例1slice文件:#ifndef HELLO
41、_ICE#define HELLO_ICEmodule Demoexception RequestCanceledException;interface Hello/ 注意元数据定义 ami, amd idempotent void sayHello(int delay) throws RequestCanceledException; void shutdown();#endif2.12 示例1intAsyncClient:run(int argc, char* argv) if(argc 1) cerr appName() : too many arguments propertyToPr
42、oxy(Hello.Proxy); if(!hello) cerr argv0 : invalid proxy endl; return EXIT_FAILURE; menu(); CallbackPtr cb = new Callback(); char c;do try cout ; cin c; if(c = i) hello-sayHello(0); else if(c = d) hello-begin_sayHello(5000, newCallback_Hello_sayHello(cb, &Callback:response, &Callback:exceptio
43、n); else if(c = s) hello-shutdown(); else cout unknown command c endl; menu(); catch(const Ice:Exception& ex) cerr ex endl; while(cin.good() & c != x); return EXIT_SUCCESS;3. AMD编程3.1元数据标记3.2 AMD语言映射(C+)3.3 AMD方式下的异常3.4示例 3. AMD编程回顾AMD概述(1.3节)AMD:使用 AMD 时,服务器可以接收一个请求,然后挂起其处理,以尽快释放分派线程。当处理恢复、
44、结果已得出时,服务器要使用 Ice run time 提供的回调对象,显式地发送响应。AMD 操作通常会把请求数据 (也就是,回调对象和操作参数)放入队列 ,供应用的某个线程 (或线程池)随后处理用。这样,服务器就使分派线程的使用率降到了最低限度,能够高效地支持数千并发客户。 3. 2 AMD方式的语言映射2. AMD的语言映射(C+)C+ 代码生成器为每个AMD 操作生成以下代码: 一个抽象的回调类:实现用它来通知 Ice run time,操作已完成。类名规则:AMD_class_op例如,对于在接口I 中定义的名叫foo 的操作 ,对应的类的名字是 AMD_I_foo。void ice_
45、response();服务器可以用 ice_response 方法报告操作已成功完成。如果操作的返回类型不是 void, ice_response 的第一个参数就是返回值。与操作的out 参数对应的参数跟在返回值后面,其次序是声明时的次序。void ice_exception(const Ice:Exception &) :服务器可以用这个版本的 ice_exception报告用户异常或本地异常。void ice_exception(const std:exception &):服务器可以用这个版本的 ice_exception报告标准的异常。void ice_exceptio
46、n():服务器可以用这个版本的 ice_exception报告未知异常 3.2 AMD方式的语言映射2. AMD的语言映射(C+)(2)分派方法:其名字有后缀 _async。这个方法的返回类型是 void第一个参数是一个智能指针,指向上面描述的回调类的一个实例。其他的参数由操作的各个 in参数组成,次序是声明时的次序. 3.2 AMD方式的语言映射interface I amd int foo(short s, out long l);下面是为操作foo 生成的回调类:class AMD_I_foo : public . public:void ice_response(Ice:Int, Ic
47、e:Long);void ice_exception(const Ice:Exception &);void ice_exception(const std:exception &);void ice_exception();下面是为操作foo 的异步调用生成的分派方法:void foo_async(const AMD_I_fooPtr &, Ice:Short); 3. 3 AMD的异常传递 在两种处理上下文中, AMD 操作的逻辑实现可能需要报告异常:分派线程 ( 也就是,接收调用的线程),以及响应线程 (也就是,发送响应的线程 )。 尽管建议你用回调对象来把所有异
48、常报告给客户,实现抛出异常也是合法的,但只能在分派线程中抛出。 Ice run time 无法捕捉从响应线程抛出的异常;应用的运行时环境将决定怎样处理这样的异常。因此,响应线程必须确保抓住所有异常,并用回调对象发送适当的响应。否则,如果响应线程被未捕捉的异常终止,请求就可能不会完成,客户将无限期地等待响应。 3. 4 示例Slice定义interface Hello ami, amd idempotent void sayHello(int delay) throws RequestCanceledException; void shutdown();3. 4 示例服务端声明文件代码:#inc
49、lude #include class HelloI : virtual public Demo:Hellopublic: HelloI(const WorkQueuePtr&); / 分派函数 virtual void sayHello_async(const Demo:AMD_Hello_sayHelloPtr&, int, const Ice:Current&); virtual void shutdown(const Ice:Current&);private: WorkQueuePtr _workQueue;3. 4 示例服务端实现文件代码:Hello
50、I:HelloI(const WorkQueuePtr& workQueue) : _workQueue(workQueue)voidHelloI:sayHello_async(const Demo:AMD_Hello_sayHelloPtr& cb, int delay, const Ice:Current&) if(delay = 0) cout Hello World! ice_response(); else _workQueue-add(cb, delay); voidHelloI:shutdown(const Ice:Current& curr) c
51、out Shutting down. destroy(); curr.adapter-getCommunicator()-shutdown();3. 4 示例服务端实现文件代码:intAsyncServer:run(int argc, char* argv) if(argc 1) cerr appName() : too many arguments createObjectAdapter(Hello); _workQueue = new WorkQueue(); Demo:HelloPtr hello = new HelloI(_workQueue); / Demo:HelloPtr hello = new HelloI(_workQueue); /定义服务端定义服务端servrantservrant adapter-add(hello, communicator()-stringToIdentity(“hello”); / / 将将serverantserverant加入适配
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 委托加工合同模板3篇
- 代理投票授权3篇
- 二手商业店买卖合同样本3篇
- 劳动合同解除决定通知协议决定3篇
- 户口迁移的严肃承诺3篇
- 保密性托管服务协议3篇
- 废品交易协议3篇
- 代为办理房产交易的委托书3篇
- 煤炭批发区域市场差异考核试卷
- 老年人辅助包装考核试卷
- 流动式起重机(固定)定期检验-自检记录
- 耳鼻咽喉科-咽肿瘤
- 宿舍楼设计开题报告
- 邻苯二甲酸二辛酯MSDS
- 电梯日常检查记录
- 教育的起源和古代东方文明古国的教育
- 有机化学6章对映异构-课件
- 抗菌药物使用强度(DDD)解析与控制
- T∕CACM 1064-2018 针刀医学临床 通用要求
- 招聘求职简历制作表格模板可编辑下载 精品简历模板 标准表格单页02
- 凑十法加法竖式运算(可打印)
评论
0/150
提交评论