Chris Stith wrote:
> The documentation for a library should state whether or not it is
> thread-safe. Serializing calls to a library certainly doesn't make
> it thread-safe, but serializing calls to individual nonreentrant
> functions within the library keeps them from puking all over your
> program.
>
> My suggestion is to let libraries that are threadsafe (system
> libraries as well as Perl moduels would be nice) be used as such
> so the advantages of that can be realized, while at the same time
> defaulting to serialized calls for libraries which are not, so
> your threaded programs which need to call nonreentrant functions
> can do so with some level of safety.
Thread safety actually comes in a series of flavours - see the manpage
excerpt below. Also, assuming that the same level of MT-safeness applies to
the whole of a library is incorrect - take for example libc, which contains
everything from Unsafe to Async-signal-safe functions.
Alan Burlison
Standards, Environments, and Macros attributes(5)
MT-Level
Libraries are classified into four categories which define
their ability to support multiple threads. Manual pages con-
taining routines that are of multiple or differing levels
show this within their NOTES or USAGE section.
Safe Safe is an attribute of code that can be called from a
multithreaded application. The effect of calling into
a Safe interface or a safe code segment is that the
results are valid even when called by multiple
threads. Often overlooked is the fact that the result
of this Safe interface or safe code segment can have
global consequences that affect all threads. For
example, the action of opening or closing a file from
one thread is visible by all the threads within a pro-
cess. A multi-threaded application has the responsi-
bility for using these interfaces in a safe manner,
which is different from whether or not the interface
is Safe. For example, a multi-threaded application
that closes a file that is still in use by other
threads within the application is not using the
close(2) interface safely.
Unsafe
An Unsafe library contains global and static data that
is not protected. It is not safe to use unless the
application arranges for only one thread at time to
execute within the library. Unsafe libraries may con-
tain routines that are Safe; however, most of the
library's routines are unsafe to call.
The following table contains reentrant counterparts
for Unsafe functions. This table is subject to change
by Sun.
Reentrant functions for libc:
Unsafe Function Reentrant counterpart
ctime ctime_r
localtime localtime_r
asctime asctime_r
gmtime gmtime_r
ctermid ctermid_r
getlogin getlogin_r
rand rand_r
readdir readdir_r
strtok strtok_r
tmpnam tmpnam_r
MT-Safe
An MT-Safe library is fully prepared for multithreaded
access. It protects its global and static data with
locks, and can provide a reasonable amount of con-
currency. Note that a library can be safe to use, but
not MT-Safe. For example, surrounding an entire
library with a monitor makes the library Safe, but it
supports no concurrency so it is not considered MT-
Safe. An MT-Safe library must permit a reasonable
amount of concurrency. (This definition's purpose is
to give precision to what is meant when a library is
described as Safe. The definition of a Safe library
does not specify if the library supports concurrency.
The MT-Safe definition makes it clear that the library
is Safe, and supports some concurrency. This clari-
fies the Safe definition, which can mean anything from
being single threaded to being any degree of mul-
tithreaded.)
Async-Signal-Safe
Async-Signal-Safe refers to particular library rou-
tines that can be safely called from a signal handler.
A thread that is executing an Async-Signal-Safe rou-
tine will not deadlock with itself if interrupted by a
signal. Signals are only a problem for MT-Safe rou-
tines that acquire locks.
Signals are disabled when locks are acquired in
Async-Signal-Safe routines. This prevents a signal
handler that might acquire the same lock from being
called. The list of Async-Signal-Safe functions
includes:
_exit access aio_error
aio_return aio_suspend alarm
cfgetispeed cfgetospeed cfsetispeed
cfsetospeed chdir chmod
chown clock_gettime close
creat dup dup2
execle execve fcntl
fdatasync fork fstat
fsync getegid geteuid
getgid getgroups getpgrp
getpid getppid getuid
kill link lseek
mkdir mkfifo open
pathconf pause pipe
read rename rmdir
sem_post sema_post setgid
setpgid setsid setuid
sigaction sigaddset sigdelset
sigemptyset sigfillset sigismember
sigpending sigprocmask sigqueue
sigsuspend sleep stat
sysconf tcdrain tcflow
tcflush tcgetattr tcgetpgrp
tcsendbreak tcsetattr tcsetpgrp
thr_kill thr_sigsetmask time
timer_getoverrun timer_gettime timer_settime
times umask uname
unlink utime wait
waitpid write
MT-Safe with Exceptions
See the NOTES or USAGE sections of these pages for a
description of the exceptions.
Safe with Exceptions
See the NOTES or USAGE sections of these pages for a
description of the exceptions.
Fork1-Safe
A Fork1-Safe library releases the locks it had held
whenever fork1(2) is called in a Solaris thread pro-
gram, or fork(2) in a POSIX (see standards(5)) thread
program. Calling fork(2) in a POSIX thread program
has the same semantic as calling fork1(2) in a Solaris
thread program. All system calls, libpthread, and lib-
thread are Fork1-Safe. Otherwise, you should handle
the locking clean-up yourself (see
pthread_atfork(3THR)).
Cancel-Safety
If a multi-threaded application uses
pthread_cancel(3THR) to cancel (that is, kill) a
thread, it is possible that the target thread is
killed while holding a resource, such as a lock or
allocated memory. If the thread has not installed the
appropriate cancellation cleanup handlers to release
the resources appropriately (see
pthread_cancel(3THR)), the application is "cancel-
unsafe", that is, it is not safe with respect to can-
cellation. This unsafety could result in deadlocks due
to locks not released by a thread that gets cancelled,
or resource leaks; for example, memory not being freed
on thread cancellation. All applications that use
pthread_cancel(3THR) should ensure that they operate
in a Cancel-Safe environment. Libraries that have can-
cellation points and which acquire resources such as
locks or allocate memory dynamically, also contribute
to the cancel-unsafety of applications that are linked
with these libraries. This introduces another level of
safety for libraries in a multi-threaded program:
Cancel-Safety. There are two sub-categories of
Cancel-Safety: Deferred-Cancel-Safety, and
Asynchronous-Cancel-Safety. An application is con-
sidered to be Deferred-Cancel-Safe when it is Cancel-
Safe for threads whose cancellation type is
PTHREAD_CANCEL_DEFERRED. An application is considered
to be Asynchronous-Cancel-Safe when it is Cancel-Safe
for threads whose cancellation type is
PTHREAD_CANCEL_ASYNCHRONOUS. Deferred-Cancel-Safety is
easier to achieve than Asynchronous-Cancel-Safety,
since a thread with the deferred cancellation type can
be cancelled only at well-defined cancellation points,
whereas a thread with the asynchronous cancellation
type can be cancelled anywhere. Since all threads are
created by default to have the deferred cancellation
type, it may never be necessary to worry about asyn-
chronous cancel safety. Indeed, most applications and
libraries are expected to always be Asynchronous-
Cancel-Unsafe. An application which is Asynchronous-
Cancel-Safe is also, by definition, Deferred-Cancel-
Safe.