Using Threads with ISB for C++
For platforms that support threads, ISB for C++ provides two sets of libraries; a single-threaded library and another library that is thread-safe and re-entrant. In addition to providing thread-safe facilities for client applications, the multi-threaded version of the library results in the internal use of threads by the ISB for C++ core.
For applications that never intend to use threads, the single-threaded library offers slightly better performance. Both libraries provide identical interfaces, which allows your applications to take advantage of multi-threaded support in the future without worrying about interface changes.
NOTE: The Dispatcher class is useful for single-threaded applications only.
NOTE: If a particular client thread issues multiple bind requests to the same object implementation, ISB for C++ will not establish multiple connections. Instead, ISB for C++ will detect that a connection already exists and will re-use that connection.Figure 7.2 One bind for multiple client application threads.
_clone
method on the object reference, resulting in a new connection with the object implementation and the spawning of a new worker thread. You should remember that the _duplicate method increases the reference count to the object and that _clone makes a complete copy of the object reference and results in a new, separate connection.
File name | Description |
liborb_r.so | Re-entrant version of the library liborb.so |
liborb_r.a | Re-entrant version of the library liborb.a |
For Windows and Windows/NT, this library should be used:
File name | Description |
ORB_R.DLL | Re-entrant version of the library ORB.DLL |
Event Loop Integration
When your object implementation invokes the BOA::impl_is_ready
method, an event loop is entered that waits for requests from client applications. Your object implementation may also need to interact with another event-driven system. In a multi-threaded environment, you can solve this problem by simply using two threads; one thread waits for ISB for C++ events and the other thread services other events. If your platform does not support threads, you may find it helpful to integrate all event driven processing by using the Dispatcher
and IOHandler
classes.
The Dispatcher Class
This class is designed to detect events on several file descriptors and dispatch those events to the appropriate handler. The Dispatcher
maintains three lists of file descriptors; one list for reading data, one list for writing data and one for exceptions. You can use the link
method to add a file descriptor to one of the Dispatcher
class' lists and define the IOHandler
object to be called to handle events on that file descriptor. You can find the include file for the Dispatcher class in include/dispatcher/dispatch.h.
NOTE: The Dispatcher class is useful for single-threaded applications only.An application should have only one instance of the
Dispatcher
class and the static instance
method is provided to create the object, if necessary, and return a pointer to it.
The Dispatcher
class.
class Dispatcher {
public:
enum DispatcherMask {
ReadMask,
WriteMask,
ExceptMask
};
Dispatcher();
virtual ~Dispatcher();
virtual voidlink
(int fd, DispatcherMask, IOHandler*);
virtual IOHandlerhandler
(int fd, DispatcherMask) const;
virtual voidunlink
(int fd);
virtual voidstartTimer
(long sec, long usec, IOHandler*);
virtual voidstopTimer
(IOHandler*);
virtual iv_booleandispatch
(long& sec, long& usec);
virtual iv_booleandispatch
(timeval *);
virtual iv_booleandispatch
();
static Dispatcher&instance
();
...
};
link
method to add a file descriptor to the Dispatcher
, you specify the file descriptor, the DispatcherMask
and a pointer to an IOHandler object
. The DispatcherMask
value determines whether the file descriptor is added to the read, write or exception event list.
When an event occurs on the file descriptor, the Dispatcher
will invoke the appropriate IOHandler method to service the event. The IOHandler object provides methods for reading data from or writing data to a file descriptor as well as for handling exceptions and expired timers. If an IOHandler
method returns a negative value indicating it encountered an error, the Dispatcher
will automatically unlink the IOHandler
from its file descriptor.
NOTE:
You must make multiple invocations of the link method if you want a particular
file descriptor to be placed in more than one of the dispatcher's lists.
DispatcherMask values cannot be ordered together when calling link
.
You can use the handler method to return the IOHandler object defined for a particular file descriptor and DispatcherMask combination.
IOHandler
object by invoking the startTimer
method. This method lets you specify a time interval in a combination of seconds and microseconds. When the interval expires, the IOHandler
object's timerExpired
method is invoked.The Dispatcher
method stopTimer
can be called to stop a timer.
NOTE: Timers are not periodic. You must set them each time you want to time another interval.Timer methods can be especially useful in single-threaded environments. Multi-threaded applications have the flexibility of starting timers in separate threads.
dispatch
method accepts no arguments and blocks indefinitely or until an event occurs on one of its file descriptors. If a file descriptor event occurs, the appropriate IOHandler
method is invoked before the dispatch
method returns.
The other two forms of the dispatch
method accept a time interval specification. If the time interval specified is zero, the Dispatcher
will return immediately after checking all the file descriptors and timers. If the time interval is greater than zero, the Dispatcher
will block until an event occurs on one of the file descriptors or until the time interval expires. The dispatch
method returns a one if an event on a file descriptor caused the return. This method returns a zero if an expired timer caused the dispatch
method to return.
unlink
method removes the specified file descriptor from all lists maintained by the Dispatcher
.
IOHandler
class to handle events on a particular file descriptor. You associate your IOHandler
object with a file descriptor, using the Dispatcher
object's link
method.
IOHandler
class.
classIOHandler
{
protected:
IOHandler();
public:
virtual ~IOHandler();
virtual intinputReady
(int fd);
virtual intoutputReady
(int fd);
virtual intexceptionRaised
(int fd);
virtual void timerExpired(long sec, long usec);
};
Dispatcher
class assumes your methods will follow.
Table 7.1 The IOHandler class methods
Using an IOHandler
To create your own IOHandler
, simply derive your own class and implement those methods you intend to use. The following code example shows an example IOHandler-derived class.
An example IOHandler
-derived class.
#include <dispatch/iohandle.h>
The following code example shows how you might instantiate your handler and link it to a file descriptor. In this example, when an input event occurs on
...
class MyHandler
: public IOHandler
{
public:
MyHandler();
virtual ~MyHandler();
virtual int inputReady
(int fd) {
// read from file using fd
...
if(done) {
return(0);
} else if (more_left_to_read) {
return(1);
} else if (failure) {
return(-1);
}
}
...
};myfd
the dispatcher will call my_handler::inputReady
method to handle the event.
Instantiating and linking a handler to a file descriptor.
...
MyHandler my_handler;
Dispatcher &disp = Dispatcher::instance();disp.link(myfd, Dispatcher::ReadMask, my_handler);
... Integration with XWindows
NOTE: This implementation is for single-threaded servers only.ISB for C++ provides an
XDispatcher
class that you can use to integrate your application with the XWindows XtMainLoop. The XDispatcher
registers the file descriptors it uses for its connections with the Xt event loop and installs the appropriate event handlers. The result is that the Xt event loop receives and dispatches events for both XWindow and ISB for C++ events. When an event occurs on one of ISB for C++'s file descriptors, the Xt event loop will call the appropriate ISB for C++ method to process the data.
The following code example shows how you might use the XDispatcher
class in your object implementation. Applications that use the XDispatcher
class should link with the library libxdispatch.a
in addition to all the other appropriate ISB for C++ libraries.
Using the XDispatcher
class.
#include <dispatch/xdisp.h>
int main(int argc, char * const *argv)
{
// Instantiate XDispatcher before invoking any ISB for C++ methods.
XDispatcher xdisp;
// Initialize ORB and BOA.
CORBA::ORB_ptr orb = CORBA::ORB_init(argc, argv);
CORBA::BOA_ptr boa = orb->BOA_init(argc, argv);
...
boa->impl_is_ready();
// You can call XtMainLoop() instead of impl_is_ready().
...
}
NOTE: This implementation is for single-threaded servers only.ISB for C++ provides a
WDispatcher
class that you can use to integrate ISB for C++ events with Windows message events. The WDispatcher
must be instantiated before any ORB object implementations are instantiated and before ORB or BOA methods are invoked. When you instantiate the WDispatcher object, you must pass it the window handle.
NOTE: There are significant advantages to building a multithreaded server rather than integrating the orb with the Windows event loop. For more information, see Multithreaded Servers and Windows 95/Windows NT later in this chapter.Using the
WDispatcher
class with the Windows event loop.
#include <dispatch/wdisp.h>
...
// Windows main entry point
WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR, int nCmdShow)
{
static char szAppName[] = "Library";
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
// Initialize wndclass
...
hwnd = CreateWindow(szAppName, "LibraryServer", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 200, 200,
NULL, NULL, hInstance, NULL);
WDispatcher *winDispatcher = new WDispatcher(hwnd);
CORBA::ORB_var orb = CORBA::ORB_init(__argc, __argv);
CORBA::BOA_var orb = orb->BOA_init(__argc, __argv);
Library server("Harvard");
boa->obj_is_ready(&server);
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
// Enter message loop
while(GetMessage(&msg, NULL, 0, 0) ) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
NOTE: This implementation is for single-threaded servers only.You may also use the WDispatcher class when developing client applications with the Microsoft Foundation Classes. When you derive your application class from the Microsoft CWinApp class, you need to provide an InitInstance method. The WDispatcher object should be instantiated in the InitInstance method. Using the
WDispatcher
with MFC-based applications.
#include <afxwin.h>#include <dispatch/wdisp.h>
...
// Application classclass LibraryClientApp : public CWinApp {
public:
BOOL InitInstance();
...
};
BOOL LibraryClientApp::InitInstance()
{
m_pMainWnd = new MainWindow;
m_pMainWnd->showWindow(m_nCmdShow);
m_pMainWnd->UpdateWindow();
// WDispatcher instantiation goes here.
WDispatcher *winDispatcher = new WDispatcher(m_pMainWnd);
CORBA::ORB_var orb = CORBA::ORB_init(__argc, __argv);
return 1;
}
...
// Windows main entry pointThis example is identical to the preceding WDispatcher example, except it does not create a WDispatcher object. The event loop handles normal Windows messages as usual. ORB requests, however, do not flow through the event loop. Rather, the ORB automatically creates worker threads when a request comes in. These threads are completely independent of the Windows event loop. Creating a multithreaded server using MFC is equally straightforward.
WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR, int nCmdShow)
{
static char szAppName[] = "Library";
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
// Initialize wndclass
...
hwnd = CreateWindow(szAppName, "LibraryServer",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 200, 200,
NULL, NULL, hInstance, NULL);
CORBA::ORB_var orb = CORBA::ORB_init(__argc, __argv);
CORBA::BOA_var orb = orb->BOA_init(__argc, __argv);
Library server("Harvard");
boa->obj_is_ready(&server);
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
// Enter message loop
while(GetMessage(&msg, NULL, 0, 0) ) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
#include <stdafx.h>The
...
// Application class
class LibraryClientApp : public CWinApp
{
public:
BOOL InitInstance();
...
};
BOOL LibraryClientApp::InitInstance()
{
m_pMainWnd = new MainWindow;
m_pMainWnd->showWindow(m_nCmdShow);
m_pMainWnd->UpdateWindow();
CORBA::ORB_var orb = CORBA::ORB_init(__argc, __argv);
CORBA::BOA_var boa = orb->BOA_init(__argc, __argv);
Library server("Harvard");
boa->obj_is_ready(&server);
return 1;
}
...
InitInstance
method provides all ORB initialization. After initializing the ORB and BOA objects, the initialization code creates the Library object and declares the object is ready.
Whether the server is built directly on the Win32 API or using MFC, the multithreaded ISB for C++ library listens for incoming requests and creates worker threads to handle each request. The application need do no other thread-specific coding.
Dispatcher
.
class MyDispatcher : public Dispatcher
{
public:
MyDispatcher
();
virtual ~MyDispatcher
();
virtual void link(int fd, DispatcherMask, IOHandler*);
virtual IOHandler* handler(int fd, DispatcherMask) const;
virtual void unlink(int fd);
virtual void startTimer(long sec, long usec, IOHandler *);
virtual void stopTimer(IOHandler *);
virtual iv_boolean setReady(int, DispatcherMask)
{ return 0; } // No need to implement
virtual void dispatch();
virtual iv_boolean dispatch(long&, long& )
{ return 0; } // No need to implement
virtual iv_boolean dispatch(timeval *val);
private:
...
};
Last Updated: 02/03/98 15:32:07