Merge pull request #2222 from jwillemsen/jwi-dllexportwarning
[ACE_TAO.git] / TAO / docs / tutorials / Quoter / AMI / index.html
blob13fc15e446f01c3ecb9cab86f09044027cb17ad3
1 <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
2 <html>
3 <head>
4 <title>Asynchronous Method Invocation - CORBA for impatient clients</title>
5 <!-- -->
6 </head>
8 <BODY text = "#000000"
9 link="#000fff"
10 vlink="#ff0f0f"
11 bgcolor="#ffffff">
13 <h3>Asynchronous Method Invocation - CORBA for impatient clients</h3>
15 <P>Our <A HREF="../Simple/Client/index.html">simple client</A>
16 illustrated how to use the traditional CORBA synchronous method
17 invocation to query a number of stock prices.
18 Suppose that we had to query hundreds of stock prices, for
19 example, during the initialization of a complex market analysis
20 tool.
21 In that case sending the requests in sequence is going to yield
22 poor performance; we are not taking advantage of the natural
23 parallelism in distributed systems, since we are waiting for the
24 first response to come back before sending the next query.
25 Traditionally this problem has been attacked using either
26 <CODE>oneway</CODE> calls or multiple threads. Both approaches can
27 work, but they have some disadvantages:
28 multi-threading programming can be hard and error-prone,
29 oneways are unreliable and require callback interfaces to return
30 the stock value.
31 Recently the OMG approved the CORBA Messaging specification
32 that extends the basic invocation model to include asynchronous
33 calls.
34 Unlike the old deferred synchronous model, the new model uses
35 the IDL compiler and the SII to achieve type safety and improved
36 performance, but the application does not block waiting for a
37 response. Instead, it gives the ORB a reference to a reply
38 handler that will receive the response asynchronously.
39 The specification also defines a polling interface that we will
40 not discuss as TAO does not implement it.
41 </P>
43 <P>For this problem we will extend the IDL interface to include a
44 new operation:
45 </P>
46 <PRE>
47 interface Single_Query_Stock : Stock {
48 double get_price_and_names (out string symbol,
49 out string full_name);
51 </PRE>
52 <P>This will simplify some of the examples.
53 </P>
55 <P>The first step is to generate the stubs and skeletons with
56 support for the callback AMI. We do this with the <CODE>-GC</CODE>
57 flag:
58 </P>
59 <PRE>
60 $ $TAO_ROOT/TAO_IDL/tao_idl -GC Quoter.idl
61 </PRE>
62 <P>You may want to take a brief look at the generated client side
63 interface.
64 The IDL compiler adds new methods to the <CODE>Quoter::Stock</CODE>
65 interface. In particular pay attention to this operation:
66 </P>
67 <PRE>
68 virtual void sendc_get_price_and_names (
69 AMI_Single_Query_StockHandler_ptr ami_handler
71 </PRE>
72 <P>This is the operation used to send a request asynchronously. The
73 response is received in the handler object. This is a regular
74 CORBA object with the following IDL interface:
75 </P>
76 <PRE>
77 interface AMI_Single_Query_StockHandler {
78 void get_price_and_names (in double ami_return_val,
79 in string symbol,
80 in string full_name);
82 </PRE>
83 <P>You don't have to write this IDL interface. The IDL compiler
84 automatically generates the so-called <EM>implied IDL</EM>
85 constructs from your original IDL.
86 Notice how the arguments are generated. The first argument is
87 simply the return value, then the output arguments show up, but
88 as <EM>input</EM> only since the handler has to receive the
89 reply.
90 </P>
92 <H3>Implementing the reply handler</H3>
94 <P>We will have to implement a servant for this new IDL interface
95 so we can receive the reply,
96 exactly as we do for servers:
97 </P>
98 <PRE>
99 class Single_Query_Stock_Handler_i : public POA_Quoter::AMI_Single_Query_StockHandler
101 public:
102 Single_Query_Stock_Handler_i (int *response_count)
103 : response_count_ (response_count) {}
105 void get_price_and_names (CORBA::Double ami_return_val,
106 const char *symbol,
107 const char *full_name)
109 std::cout << "The price of one stock in \""
110 << full_name << "\" (" << symbol << ") is "
111 << ami_return_val << std::endl;
112 *this->response_count_++;
115 private:
116 int *response_count_;
118 </PRE>
119 <P>The <CODE>response_count_</CODE> field will be used to
120 terminate the client when all the responses are received.
121 </P>
123 <H3>Sending asynchronous method invocations</H3>
125 <P>The handler servant is activated as any other CORBA object:
126 </P>
127 <PRE>
128 int response_count = 0;
129 Single_Query_Stock_Handler_i handler_i (&response_count);
130 Quoter::AMI_Single_Query_StockHandler_var handler =
131 handler_i._this ();
132 </PRE>
133 <P>and now we change the loop to send all the requests at once:
134 </P>
135 <PRE>
136 int request_count = 0;
137 for (int i = 2; i != argc; ++i) {
138 try {
139 // Get the stock object
140 Quoter::Stock_var tmp =
141 factory->get_stock (argv[i]);
142 Quoter::Single_Query_Stock_var stock =
143 Quoter::Single_Query_Stock::_narrow (tmp.in ());
145 stock->sendc_get_price_and_names (handler.in ());
146 request_count++;
148 </PRE>
149 <P>after the loop we wait until all the responses have arrived:
150 </P>
151 <PRE>
152 while (response_count < request_count
153 && orb->work_pending ()) {
154 orb->perform_work ();
156 </PRE>
158 <H3>Exercise 1</H3>
160 <P>Complete the <CODE>client.cpp</CODE> file. Does this client play
161 the server role too? If not, what is the role with respect to
162 the handler servant? If you think it is a server too, what
163 should you do about the POA?
164 </P>
165 <P>You can use the following files to complete your implementation:
166 the <A HREF="Quoter.idl">Quoter.idl</A>,
167 <A HREF="Handler_i.h">Handler_i.h</A>,
168 <A HREF="Handler_i.cpp">Handler_i.cpp</A>.
169 Remember that the simple client main program
170 (located
171 <A HREF="../Simple/Client/client.cpp">here</A>)
172 is a good start.
173 </P>
175 <H4>Solution</H4>
176 <P>Look at
177 <A HREF="client.cpp">client.cpp</A> file. It should
178 not be much different from yours.
179 </P>
181 <H3>Testing</H3>
183 <P>A simple server is provided, based on the
184 <A HREF="../Simple/Server/index.html">simple server</A>
185 from the introduction.
186 As before, you need the following files:
187 <A HREF="Stock_i.h">Stock_i.h</A>,
188 <A HREF="Stock_i.cpp">Stock_i.cpp</A>,
189 <A HREF="Stock_Factory_i.h">Stock_Factory_i.h</A>
190 <A HREF="Stock_Factory_i.cpp">Stock_Factory_i.cpp</A>
191 and <A HREF="server.cpp">server.cpp</A>.
192 </P>
194 <H2>Configuration</H2>
196 <P>So far we have used the default configuration in TAO,
197 but AMI works better with some fine tuning. For example,
198 by default TAO uses a separate connection for each outstanding
199 request. With SMI this is a very good strategy, as separate
200 threads can send concurrent requests without any shared
201 resources,
202 but this approach does not scale well with AMI, as it would
203 create too many connections.
204 The solution is to change the strategy to share connections.
205 All we need to do is create a
206 <A HREF="svc.conf">svc.conf</A> file with the following
207 contents:
208 </P>
209 <PRE>
210 static Client_Strategy_Factory "-ORBTransportMuxStrategy MUXED"
211 </PRE>
212 <P>There are many other configuration options, all of them
213 documented in
214 <A HREF="../../../Options.html">Options.html</A>,
216 <A HREF="../../../configurations.html">configurations.html</A>,
217 and in the Developer's Guide available from
218 <A HREF="http://www.theaceorb.com/">OCI</A>.
219 </P>
221 <hr>
222 <address><a href="mailto:coryan@cs.wustl.edu">Carlos O'Ryan</a></address>
223 </body>
224 </html>