Copyright © TIBCO Software Inc. All Rights Reserved
Copyright © TIBCO Software Inc. All Rights Reserved


Chapter 8 Advanced Features : Multithreaded Adapters

Multithreaded Adapters
The TIBCO Adapter SDK allows flexible, platform-independent multithreading. This section discusses the following aspects of multithreaded adapters:
Deciding on Multithreaded Implementation
A thoughtful multithreaded design may help a custom adapter achieve a greater level of concurrency and performance in terms of latency.
Consider carefully whether the custom adapter requires multiple threads. Threads result in a more complex programming logic and are therefore more error-prone and more difficult to debug. In addition, a multithreaded SDK-based adapter consumes more resources than a single-threaded one on a single-CPU machine.
To fully exploit a multiprocessor system, the custom adapter running on it should also be multithreaded.
Multithreading is useful for a server that takes one request at a time, and then spends most of its time blocking on I/O. In this case, the server would have unacceptable performance running as a single-threaded application. With a pool of threads, each thread can work on one request and several requests can be handled simultaneously, making use of otherwise idle processor cycles.
Processing resources may not be the only factor hindering adapter performance. The interface supported by the target application can also be a bottleneck that eliminates any benefit resulting from multithreading the adapter. Multithreading cannot address performance issues caused by system resource bottlenecks.
While TIBCO Messaging delivers messages in the order sent to the adapter on a single transport, a multithreaded adapter may not process the messages in the order received.
All C++ custom adapters that implement multithreading must set the multithread behavior in C++ SDK by calling the MAppProperties::setMultiThreaded().
Multithreading and MDispatcher
It is recommended to make an adapter multithreaded using the TIBCO Adapter SDK MDispatcher class. The different constructors for MDispatcher allow you to associate each instance with either an MApp application manager or with an MApp and an MSession.
Custom adapters can create an instance of MDispatcher to spawn a thread that dispatches events for a given session. The MDispatcher class can be used with both MRvSession and MJmsSession.
Creating a multithreaded adapter is typically a matter of determining which session requires additional threads and constructing the appropriate MDispatcher objects.
MDispatcher is used in conjunction with MSubscriber but not with MPublisher.
Other SDK Objects
In addition to the new MDispatcher class, the following classes can be used in a multithreaded fashion:
MClassRegistry is thread safe and thread aware. As a result, you can serialize and deserialize across threads.
MTrace is thread safe and thread aware. You can therefore perform tracing across threads.
The SDK may need to handle events that are not attached to any explicit MSession, for example, TIBCO Hawk messages or internal events. These events must be handled through the main MApp event manger with the MApp::nextEvent() call.
If MApp::start() is called with no arguments or with Mtrue, the SDK handles these events automatically. The correct synchronized shutdown behavior of a multithreaded adapter depends on dispatching these events. If an adapter fails to ensure that MApp::nextEvent() is called during shutdown, the behavior of the SDK is undefined.
Multithreading Scenarios
This section gives an overview of multithreading scenarios.
Single Event Queue
If all the dispatchers you created are associated with one session (and therefore with a single event queue), the multithreading adapter program proceeds as follows:
1.
2.
3.
Figure 21 Multithreading for Single Event Queue
Queue Group
If you are using a queue group, there are two options for handling multithreading.
Associate the MDispatcher with MApp. This gives each session equal weight when a thread becomes available.
Associate MDispatcher instances with individual sessions managed by MApp.
You can also use a combination approach, that is, associate some MDispatchers with MApp, then create additional dispatchers and associated it with a session that has priority over all other sessions.
Writing a Multithreaded Adapter with the C++ SDK
To write a multithreaded C++ custom adapter:
1.
When setting up the MAppProperties instance for the adapter, call MAppProperties::setMultiThreaded(); to turn on multi-threading.
You can turn multi-threading off by calling MAppProperties::setMultiThreaded (MFalse).
The C++ SDK is single-threaded by default and will only behave correctly for multithreaded custom adapters that make this call. The following example fragment from mt_rpc shows how the call is made as part of main().

 
int main(int argc, char** argv) {
   MAppProperties appProperties;
   appProperties.set( MAppProperties::APPNAME, "mt_rpc");
   appProperties.set( MAppProperties::APPVERSION, "5.0.0");
   appProperties.set( MAppProperties::APPINFO, "SDK multi-threaded RPC example");
   appProperties.set( MAppProperties::APPCONFIGURL,                        "/tibco/private/adapter/examples/mt_rpc/mt_rpc_client");
   appProperties.set( MAppProperties::APPREPOURL, "tibcr://CPP_EXAMPLES");
   appProperties.setMultiThreaded();
   OrderAdapter myAdapter(appProperties);
   myAdapter.start();
}

 
2.
In MApp::onInitialization(), construct as many instances of MDispatcher as required.
In the example below, the dispatchers are associated with a session.

 
void OrderServer::onInitialization() throw(MException){
   // create dispatchers which will handle event dispatching in a
   // platform-independent way for a given MRvSession
   m_pDispatchers = new MList<MDispatcher *>();
   MRvSession *pSession = MRvSession::downCast(
                              this->getComponentByName(RVSESSION_NAME) );
   m_NumDispatchers = 5;
   if ( pSession ) {
      for (unsigned int i=0; i<m_NumDispatchers; ++i ) {
         MDispatcher *pDispatcher = new MDispatcher(this, pSession );
         m_pDispatchers->push_back( pDispatcher );
      }
   }
   printf( "RPC Server - Ready with %u MDispatchers\n",
                         m_NumDispatchers );

}
Writing a Multithreaded Adapter with the Java SDK
The mt_pubsub demonstrates how to write a multithreaded adapter using MDispatcher. Each time an instance of MDispatcher is created, a new thread is spawned to dispatch incoming events on the relevant MSession. The additional threads allow the subscriber to remain responsive facing lengthy operations.
1.
In the onInitialization() method, create instances of MDispatcher, as follows. The dispatchers are associated with a session.

 
protected void onInitialization() throws MException
{
MComponentRegistry registry = getComponentRegistry();
 
MSubscriber sub = registry.getSubscriber("sub");
if (null == sub) {
throw new MException("PUBSUB-0003", "sub");
}
// attach an event listener to the subscriber
sub.addListener(new DataEventHandler());
 
// create 5 dispatchers for the session that is associated
// with the subscriber
MSession session = sub.getSession();
for (int i = 0; i < NO_OF_DISPATCHERS; ++i) {
dispatchers.add( new MDispatcher(this, session) );}
}

 
2.
In onTermination(), you must stop all the dispatchers created earlier.

 
protected void onTermination() throws MException
{
// stop all the dispatchers that were created during       //onInitialization
 
System.out.println(new Date() + " Stopping all the
      dispatchers...");
MDispatcher dispatcher = null;
for (int i = 0; i < NO_OF_DISPATCHERS; ++i) {
dispatcher = (MDispatcher)dispatchers.get(i);
dispatcher.stop();
}
System.out.println(new Date() + " Stopped all the
      dispatchers");

Copyright © TIBCO Software Inc. All Rights Reserved
Copyright © TIBCO Software Inc. All Rights Reserved