home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
threads.zip
/
readme.txt
< prev
Wrap
Text File
|
1996-02-27
|
12KB
|
308 lines
DISCLAIMER
----------
Nothing in this package should be take to imply any plans are in place
to satisfy any of the requirements listed in this document. The
interfaces and functions supplied by this prototype will certainly
change before this type of support appears in the product, if it ever
appears in the product.
Support will be provided only as time allows and given our current
release schedule it looks like there will be no time for supporting
this package.
We are however interested in feedback and comments. Especially
regarding your requirements for multi-threaded support in the Visual
Builder and the notification framework. Send comments to Steve
Wasleski (WASLESKI at CARY).
MOTIVATIONS
-----------
During the development of a Conversational Communication Class Library
for VisualAge C++ the following problems were encountered and had to
be solved. The solution to these problems is contained in this package.
1) The VisualAge C++ Visual Builder and Open Class Library notification
framework do not support multi-threaded parts.
2) Background (non-GUI) threads or applications (server applications in
a client/server solution, for example) are also not supported. This
is primarily due to the user interface classes being the only source
of asynchronous events that start a chain of notifications.
The Conversational Communication Class Library is not in this package.
It may be available in a later version of VisualAge C++. Interested
IBMers can get a driver. Contact Paul Morris (RPMORRIS at RTPNOTES).
REQUIREMENTS
------------
The solution to our problem had to meet the following requirements.
1) Application developers that use multi-threaded parts created by
others should not need to know or care that the part spawns other
threads to do its work.
2) Notifications from the part must all be asynchronously processed
on the same thread on which it was created even if the notifyObservers
call takes place one of the part's spawned threads.
3) Event data must be supported even though the events are processed
asynchronously rather than synchronously as in the standard
notification mechanism.
4) This asynchronous notification enables other sources of asynchronous
events other than the user via the user interface class library.
This fact must be taken advantage of to support creating background
threads and applications that can be driven by these new asynchronous
event sources.
These other requirements were identified during the creation of this
prototype, but are not resolved by it.
1) Explicit IThread object support in the visual builder.
2) Asynchronous variable support. That is, a new kind of variable
that will change any regular style part's notifications into
asynchronous notifications.
3) Make a part's notification mechanism (list of observers) reentrant
on multiple threads rather than a single thread.
FILES
-----
Needed to create and use asynchronous notifiers:
THREADS.ZIP - Contains all these files except itself. Use
PKUNZIP2 -d THREADS.ZIP to unpack into current directory.
README.TXT - This file.
iasyntfy.hpp - The header file for IAsyncNotifier. Note that
IAsyncNotifier is an abstract base class and is a subclass
of IStandardNotifier.
asyncnot.dll - The DLL the contains the implementation of IAsyncNotifier.
asyncnot.LIB - The import library for asyncnot.dll.
asyncnot.vbb - Contains the IAsyncNotifier non-visual part. Note that
IAsyncNotifier is an abstract base class.
Needed to rebuild the asyncnot.dll (this is all the source code):
asyncnot.def - The module definition file
asyncnot.mak - Make file generated by WorkFrame/2
iasynbkg.cpp - Source for queuing to background threads
iasynbkg.hpp
iasyngui.cpp - Source for queuing to GUI threads
iasyngui.hpp
iasyntfy.cpp - Source code for IAsyncNotifier
iasyntfy.hpp
iasynthr.cpp - Abstract base class for queuing
iasynthr.hpp
ievntsem.cpp - A little event sem class (thanks to Rick Blevins)
ievntsem.hpp
In the SAMPLE subdirectory:
counter.vbb - Contains the sample Counter non-visual part and two visual
parts, CountMn and CountWnd, that use it. Counter is a
concrete subclass of IAsyncNotifier.
counter.hpv - Declarations of Counter features.
counter.cpv - Definitions of Counter features.
RUNNING THE SAMPLE
------------------
1) Put the asyncnot.dll in a directory in your LIBPATH. The current
directory when you run the sample is okay if you have .; in your LIBPATH.
2) Bring up the Visual Builder and load all the two VBB files (iasynfty.vbb
and counter.vbb). I suggest starting the Visual Builder from a command line
with the current directory being the SAMPLE subdirectory. The Visual
Builder exe is ICSVB.EXE.
3) Generate part source for Counter.
4) Generate part source for CountMn and CountWnd.
5) Generate main for CountMn.
6) Make sure the location of iasyntfy.hpp is in the INCLUDE and asyncnot.lib
is in the LIB environment variables. Run nmake on CountMn.mak.
7) Run CountMn.exe.
8) When the window comes up, press the 'Create new count window' button.
A connection is fired that brings up a CountWnd window. The CountWnd
part uses the Counter non-visual part that starts a thread that
increments a counter every second.
Notice that the counter advances, but does not hang the rest of the
system since it is running on a separate thread.
9) You can create multiple instances of CountWnd by returning to the
Counter Main Window and pressing the 'Create new count window' button
again.
10) To exit the sample, close down all the windows.
HOW TO CREATE MULTI-THREADED NON-VISUAL PARTS
---------------------------------------------
1) Make your parts subclasses of IAsyncNotifier rather than
IStandardNotifier.
2) If any of your notifications will have event data, create the
event data on the heap with the new operator. (The actual data,
IString, etc., not the IEventData object. It can be allocated
on the stack, since it will be copied INotificationEvent).
Do not clean up the event data as you normally would after
notifyObservers returns. You will get a chance to clean it
up later as described in number 3.
3) If any of your notifications will have event data, as described
in number 2, override IAsyncNotifier::notificationCleanUp. It
will be called after each notification has really be processed.
Your declaration will look like this:
virtual const MyClass & notificationCleanUp (
const INotificationEvent & anEvent ) const;
Your definition will look like this:
const MyClass & MyClass :: notificationCleanUp (
const INotificationEvent & anEvent ) const
{
// A subclass of MyClass must call MyClass::notificationCleanUp first.
IAsyncNotifier::notificationCleanUp ( anEvent );
// If this is an event that we have event data that we need to
// clean up, clean it up. Note that data types that fit in 4
// or less bytes will not need cleanup (int, Boolean, unsigned long,
// etc.).
switch ( anEvent.notificationId() )
{
case MyClass::event1Id :
{
MyEvent1Data * eventData = (MyEvent1Data *)(anEvent.eventData().asUnsignedLong());
delete eventData;
break;
}
case MyClass::event2Id :
{
MyEvent2Data * eventData = (MyEvent2Data *)(anEvent.eventData().asUnsignedLong());
delete eventData;
break;
}
}
return *this;
}
HOW TO USE MULTI-THREADED NON-VISUAL PARTS ON GUI THREADS
---------------------------------------------------------
Use them exactly the same way you use standard non-visual parts.
You can create multiple async parts on one thread.
Note that an async part does not have to have an action that
explicitly starts its thread(s). They could be started in
the constructor or as a by-product of normal interaction with
the part. Therefore, the threading can be completely hidden
even if it is not in our sample.
HOW TO USE MULTI-THREADED NON-VISUAL PARTS ON BACKGROUND THREADS
----------------------------------------------------------------
Use them same way you would use standard non-visual parts on a
background thread. You can create multiple async parts on one thread.
That is, create a non-visual part (standard or async). Put other
non-visual subparts (standard and/or async with at least one async
part if the part itself is not async) on this new parts composition
editor. Interconnect the part and subparts as needed.
When you application sees fit, start a background thread (perhaps
inside another async notifier) and create an instance of this new
part on that thread. Its subparts will be created and you will
have at least one (more depending on the subparts) async notifier
created on this new thread.
The rest of this can, probably should, be encapsulated within
your new part. Do what ever is needed (if anything) at least one
of the async notifiers into a state where it will produce async
events (open a conversation with a remote process, for example).
Finally call IAsyncNotifier::run on this new thread. Much like
ICurrentApplication::run, it will not return until the thread is
done with its work. In this case that is defined as all the
IAsyncNotifier instances that were created on the thread have
been deleted. When IAsyncNotifier::run returns, just run off the
end of your thread and it will terminate.
HOW TO USE MULTI-THREADED NON-VISUAL PARTS IN BACKGROUND APPLICATIONS
---------------------------------------------------------------------
This is a special case of the last section.
The difference is that thread 1 is already started for you. You just
need to Generate Main for the new part you created as described in the
last section and you will almost be there.
In the generated .mak file change /pmtype:pm to /pmtype:vio.
In the generated .app file:
Add these lines:
#ifndef _IASYNTFY_
#include <iasyntfy.hpp>
#endif
Remove these lines:
#ifndef _IWINDOW_
#include <iwindow.hpp>
#endif
#ifndef _IMSGBOX_
#include <imsgbox.hpp>
#endif
Change the main function to look like this (removed lines are
commented and the added line is flagged):
int main(int argc, char ** argv)
{
IApplication::current().setArgs(argc, argv);
TestServer1 *iPart;
// IMessageBox::Response resp = IMessageBox::unknown;
// do {
// try {
iPart = new TestServer1();
iPart->initializePart();
// }
// catch (IException& exc) {
// resp = IMessageBox(IWindow::desktopWindow()).show(exc);
// }
// }
// while (resp == IMessageBox::retry);
// if (resp == IMessageBox::cancel) IApplication::current().exit();
// IApplication::current().run();
IAsyncNotifier::run(); // This line was added.
return 0;
} //end main
You can, of course, create other background threads if you want in the
manner described in the last section.