656 Chapter 31
for (j = 0; j < loops; j++) {
loc = glob;
loc++;
glob = loc;
}
}
If multiple threads invoke this function concurrently, the final value in glob is
unpredictable. This function illustrates the typical reason that a function is not
thread-safe: it employs global or static variables that are shared by all threads.
There are various methods of rendering a function thread-safe. One way is to
associate a mutex with the function (or perhaps with all of the functions in a
library, if they all share the same global variables), lock that mutex when the func-
tion is called, and unlock it when the mutex returns. This approach has the virtue
of simplicity. On the other hand, it means that only one thread at a time can exe-
cute the function—we say that access to the function is serialized. If the threads
spend a significant amount of time executing this function, then this serialization
results in a loss of concurrency, because the threads of a program can no longer
execute in parallel.
A more sophisticated solution is to associate the mutex with a shared variable.
We then determine which parts of the function are critical sections that access the
shared variable, and acquire and release the mutex only during the execution of
these critical sections. This allows multiple threads to execute the function at the
same time and to operate in parallel, except when more than one thread needs to
execute a critical section.
Non-thread-safe functions
To facilitate the development of threaded applications, all of the functions speci-
fied in SUSv3 are required to be implemented in a thread-safe manner, except
those listed in Table 31-1. (Many of these functions are not discussed in this book.)
In addition to the functions listed in Table 31-1, SUSv3 specifies the following:
z The ctermid() and tmpnam() functions need not be thread-safe if passed a NULL
argument.
z The wcrtomb() and wcsrtombs() functions need not be thread-safe if their final
argument (ps) is NULL.
SUSv4 modifies the list of functions in Table 31-1 as follows:
z The ecvt(), fcvt(), gcvt(), gethostbyname(), and gethostbyaddr() are removed, since
these functions have been removed from the standard.
z The strsignal() and system() functions are added. The system() function is non-
reentrant because the manipulations that it must make to signal dispositions
have a process-wide effect.
The standards do not prohibit an implementation from making the functions in
Table 31-1 thread-safe. However, even if some of these functions are thread-safe on
some implementations, a portable application can’t rely on this to be the case on all
implementations.