Writing Threaded Applications [ DCE for the HP 3000 ] MPE/iX 5.0 Express III Documentation
DCE for the HP 3000
Writing Threaded Applications
The following are hints on writing multithreaded DCE applications:
* All DCE applications are multithreaded - When writing DCE
applications, keep in mind, that the DCE runtime software is
multithreaded and all DCE applications are multithreaded; even if
the application code itself does not explicitly create threads.
* Using non-thread-safe libraries - When making calls to libraries
you do not specifically know to be thread-safe, you must provide
your own locking scheme to prevent multiple threads from executing
the same library calls concurently. While a given call may appear
to be innocuous with respect to threads, it is very difficult to
know exactly what interactions can occur within the library, or
with other libraries. For example, suppose non-thread-safe
routines 1 and 2 make a call to routine A (also non-thread-safe),
if routines 1 and 2 use different mutexes to lock their calls to
routine A, then routines 1 and 2 can both get into routine A at
the same time (violating the programmer's attempt to make the
calls thread-safe).
* Using fork() in a threaded application - fork() is not allowed
from a threaded task.
* environ is a process-wide resource - Programmers must coordinate
threads that use the putenv() and getenv() interfaces to change
and read environ.
* Signal mask: a thread-specific resource - The signal mask is a
thread-specific resource; therefore, if one thread manipulates the
signal mask, it only affects signals that specific threads might
be interested in (Posix 1003.4a Draft 3 behavior).
* Handling synchronous terminating signals - The default behavior of
OSF DCE 1.0.2 is to translate synchronous terminating signals into
exceptions. If the exception is not caught, the thread that
caused the exception is terminated. Any thread that goes through
the terminate code causes the entire task to be terminated.
* Establish synchronous signal handlers using sigaction() - The
MPE/iX POSIX C Library supports the following routines for setting
up signal handlers:
signal()
sigaction()
Of these routines, only sigaction() is supported in a DCE
application. It is used to establish handlers for synchronous
signals on an individual thread basis only.
* Asynchronous signals - There is no supported mechanism for
establishing signal handlers for asynchronous signals on MPE/iX.
* Cancelling threads blocked on a system call - The HP 3000 Kernel
Threads Service provides a cancellation facility that enables one
thread to terminate another. The cancelled thread normally
terminates at a well-defined point. Terminating a thread that is
blocked while executing system code is not possible on MPE/iX;
only threads executing non-system code may be cancelled.
* Using waitpid() - The waitpid() routine allows the parent thread
to specify which child it cares about by specifying its PID. This
call only works for the initial thread; because children created
by any thread within the task are considered children of the whole
task.
* Using setjmp and longjmp - Do not use calls to setjmp and longjmp,
these routines save and restore the signal mask and could
inadvertently cause a signal that another thread is waiting on to
be masked. Instead, use _setjmp and _longjmp; these routines do
not manipulate the signal mask.
When executing _longjmp be aware of the following:
* Ensure you are returning to a state saved within the
context of the same thread.
* If you _longjmp over a TRY clause, an exception could try
to _longjmp to a stack frame that no longer exists; and
vice versa.
* Do not _longjmp out of a signal handler.
* Use pthread_yield to allow other threads processor time - If your
application is running on a single-processor machine, and you want
to permit other threads access to the processor, you can use
pthread_yield to notify the scheduler that the current thread is
willing to release the processor to other threads of the same or
higher priority. If no threads of the same or higher priority are
ready to execute, the thread continues.
An example of the use of pthread_yield is to avoid spinning in a
tight loop, such as:
while (!flag);
by using pthread_yield as:
while (!flag) pthread_yield();
Use pthread_yield with caution; misuse can cause unnecessary
context switching and increasing overhead with no increase in
"fairness." For example, it is counterproductive for a thread to
yield while it has a needed resource locked.
MPE/iX 5.0 Express III Documentation