Class Coroutine: an abstract base class for DOS coroutines.
Author: John English ([email protected]
Department of Computing
University of Brighton
Brighton BN2 4GJ, England.
Copyright (c) J.English 1993.
Permission is granted to use copy and distribute the
information contained in this file provided that this
copyright notice is retained intact and that any software
or other document incorporating this file or parts thereof
makes the source code for the library of which this file
is a part freely available.
This class provides a framework for writing DOS coroutines.
Coroutines allow you to share the available processor time
between a number of activities; when a coroutine based on
this class has nothing useful to do, it can call the member
function "pause" which will allow other coroutines to execute.
A call to "pause"will return after all the other coroutines
present in the system have had a chance to execute.
To create a coroutine using this class, you must derive a
class containing a virtual function "main" which defines
the code to be executed by your coroutine. You can then
declare instances of this class and start them executing
by calling the member function "run". Coroutines can be
terminated by calling the member function "terminate", and
you can wait for a coroutine to terminate using the member
If you find this class useful or have any suggestions as to how it
can be enhanced, please contact the author at one of the addresses
given above. E-mail and postcards will both be welcome!
2. Deriving a new coroutine class from class Coroutine.
The constructor for your derived class should invoke the constructor
for class Coroutine. The constructor for Coroutine takes a single
unsigned integer parameter which defines the stack size in bytes
to be used by the coroutine. A default stack size of 2048 bytes
will be assumed if you do not specify otherwise. Your coroutine
class must define a member function called "main" which contains
the application-specific code for your coroutine. This function
is defined as follows:
void YourCoroutineClass::main ()
// application-specific code
Having created a derived coroutine class, you can then declare
instances of this class in your program. To start executing a
coroutine called "x", simply call the member function "run" as
"Run" returns a value of 1 (TRUE) if the coroutine has successfully
been started, and 0 (FALSE) otherwise. A result of 0 indicates that
there was not enough memory to create the coroutine data structures.
Once you have started a coroutine running, it will begin executing
the member function "main" which you have provided. When a coroutine
(or the main program) has nothing to do, it should call the static
member function "pause" as follows:
This allows the next coroutine to execute. If all coroutines and
the main program call "pause" at regular intervals, the processor
time will be shared between each of the coroutines.
Note that since rescheduling only takes place when "pause" is called,
there is no need for a synchronisation mechanism such as semaphores
to allow coroutines to communicate. Coroutines can communicate with
each other simply by updating shared variables.
3. Initialisation and finalisation.
The coroutine constructor allows you to perform any initialisation
your coroutine requires. Note however that the coroutine itself
does not start executing until "run" is called. Note that calling
"run" from inside the constructor is inadvisable, as it will prevent
further derivations and will also make it difficult to deal with
errors as indicated by the result returned by "run".
Execution of the coroutine normally ends when the coroutine's main
function returns. However, the member function "terminate" can be
used to terminate a coroutine immediately, as follows:
x.terminate (); // terminate coroutine "x"
This function should be used with care, as the state of the coroutine
at the time it is called will unknown. However, since the coroutine
will always be suspended in a call to "pause", you can avoid problems
by ensuring that the coroutine is always in a state where it can be
safely terminated whenever "pause" is called.
You can also wait for a coroutine to terminate by calling the member
x.wait (); // wait for coroutine "x" to terminate
Note that if a coroutine attempts to wait for itself to terminate,
it will have its wish granted by being terminated immediately.
When you exit from a block where a coroutine has been declared, the
destructor for that coroutine will be called. The standard destructor
waits for the coroutine to terminate and then performs the necessary
tidying-up. If your derived class defines a destructor, it will be
executed BEFORE the standard destructor. The coroutine may still be
active at this point, so you should not do anything which might cause
the member function "main" to fail. Destructors should always call
"wait" to wait for the coroutine to terminate before doing anything
else. The standard structure for a destructor should therefore be
wait (); // wait for coroutine to terminate
... // destroy object as necessary
4. A plea for feedback.
If you use this class, please contact the author via the addresses
at the beginning; if you don't have e-mail access please send me a
postcard (I like postcards!) just to let me know you've looked at
it. Feel free to suggest enhancements, find bugs or (better still)
fix them and send me patches. Happy hacking!