Open System Services Programmer's Guide

When using functions that return pointers to static library data, immediately copy the data to
thread-private memory.
Beware of Libraries That Maintain Context Across Calls
Some libraries maintain context across calls. For example, the getpwent() function returns
information about the next user in the user database, with the current position kept implicitly in the
library. The setpwent() function ensures that the next call to getpwent() returns the first user
entry. A program can get unexpected results if two different threads use these functions without
synchronizing their calls.
You can use a mutex to protect implicit context maintained by a standard library, for example by
bracketing a series of library calls with the lock and unlock of a mutex. This technique should be
used only for short periods of time.
Standard libraries that use an explicit handle to identify the intended context on each call can be
used without interference between threads. File operations that use file descriptors follow this model.
Some libraries allow multiple contexts but do not support explicit context identification on all calls.
Instead, the library allows the caller to establish a current context for the process. With these
libraries, the application is responsible for ensuring that the correct context is made current while
a thread is executing. For example, the TMF transaction-demarcation jacket routines use this method,
relying on an implicit current transaction for the process.
Addressing the Thread Stack
Memory for function variables that are not declared static is allocated from the thread-private stack.
This memory is addressable only while the thread is executing. It is not addressable by other
threads; attempting to read or write variables located in another thread’s stack causes unpredictable
results.
All program data that is to be shared by multiple threads must be external data, static internal
data, or data allocated from the heap. This data should be protected by a mutex, as appropriate.
The Standard provides a set of functions to manage thread-specific data. One use of these functions
is to maintain thread global data, such as state. The interface allows you to declare destructor
functions that are invoked at thread run-down. These functions are distinct from cancellation clean-up
handlers.
Making Process-Blocking Calls
When a thread calls a Guardian procedure that blocks the process, all other threads in the process
are also prevented from executing. If a thread is blocked for a significant period of time, it can
delay or even prevent the execution of time-critical run-time functions.
Examples of programs that can block include:
Pathway servers, which can wait indefinitely while reading $RECEIVE
The Inspect, Native Inspect, and Visual Inspect symbolic debuggers, whose use can block a
process indefinitely
Using Nowait Input or Output
Programs that use threads cannot call the Guardian AWAITIO or AWAITIOX procedure with -1
as a file parameter (applying the call to the oldest incomplete operation pending on each file).
AWAITIOX can be used to poll for completion on a specific file, although a thread must complete
all nowait input or output operations before yielding control to another thread. In summary:
No calls to AWAITIO[X]() with a file number of -1 are made outside of pthreads.
No calls to AWAITIO[X]() with a file number registered with pthreads are made outside of
pthreads.
Threading Considerations 329