Multithreaded Programming Guide

Chapter 7 Safe and Unsafe Interfaces

This chapter defines MT-safety levels for functions and libraries. This chapter discusses the following topics:

Thread Safety

Thread safety is the avoidance of data races. Data races occur when data are set to either correct or incorrect values, depending upon the order in which multiple threads access and modify the data.

When no sharing is intended, give each thread a private copy of the data. When sharing is important, provide explicit synchronization to make certain that the program behaves in a deterministic manner.

A procedure is thread safe when the procedure is logically correct when executed simultaneously by several threads. At a practical level, safety falls into the following recognized levels.

An unsafe procedure can be made thread safe and able to be serialized by surrounding the procedure with statements to lock and unlock a mutex. Example 7–1 shows three simplified implementations of fputs() , initially thread unsafe.

Next is a serializable version of this routine with a single mutex protecting the procedure from concurrent execution problems. Actually, the single mutex is stronger synchronization than is usually necessary. When two threads are sending output to different files by using fputs(), one thread need not wait for the other thread. The threads need synchronization only when sharing an output file.

The last version is MT-safe. This version uses one lock for each file, allowing two threads to print to different files at the same time. So, a routine is MT-safe when the routine is thread safe, and the routine's execution does not negatively affect performance.


Example 7–1 Degrees of Thread Safety

/* not thread-safe */
fputs(const char *s, FILE *stream) {
    char *p;
    for (p=s; *p; p++)
        putc((int)*p, stream);
}

/* serializable */
fputs(const char *s, FILE *stream) {
    static mutex_t mut;
    char *p;
    mutex_lock(&m);
    for (p=s; *p; p++)
        putc((int)*p, stream);

    mutex_unlock(&m);
}

/* MT-Safe */
mutex_t m[NFILE];
fputs(const char *s, FILE *stream) {
    char *p;
    mutex_lock(&m[fileno(stream)]);
    for (p=s; *p; p++)
        putc((int)*p, stream);
    mutex_unlock(&m[fileno(stream)]0;
}

MT Interface Safety Levels

The man pages for functions and interfaces indicate how well the function or interface supports threads. The ATTRIBUTES section of each man page lists the MT-Level attribute, which is set to one of the safety level categories listed in Table 7–1. These categories are explained more fully in the attributes(5) man page.

If a man page does not state explicitly that a function is MT-Safe, you must assume that the function is unsafe.

Table 7–1 Interface Safety Levels

Category 

Description 

Safe 

This code can be called from a multithreaded application 

Safe with exceptions 

See the NOTES sections of the man page for a description of the exceptions. 

Unsafe 

This interface is not safe to use with multithreaded applications unless the application arranges for only one thread at a time to execute within the library. 

MT-Safe 

This interface is fully prepared for multithreaded access. The interface is both safe and supports some concurrency.

MT-Safe with exceptions 

See the NOTES sections of the man page for a description of the exceptions. 

Async-Signal-Safe 

This routine can safely be called from a signal handler. A thread that is executing an Async-Signal-Safe routine does not deadlock with itself when interrupted by a signal. See Async-Signal-Safe Functions in Solaris Threads

Fork1–Safe 

This interface releases locks it has held whenever Solaris fork1(2) or POSIX fork(2) is called.

Some functions have purposely not been made safe for the following reasons.


Note –

The only way to be certain that a function with a name not ending in “_r” is MT-Safe is to check the function's manual page. Use of a function identified as not MT-Safe must be protected by a synchronizing device or by restriction to the initial thread.


Reentrant Functions for Unsafe Interfaces

For most functions with unsafe interfaces, an MT-Safe version of the routine exists. The name of the MT-Safe routine is the name of the Unsafe routine with “_r” appended. For example, the MT-Safe version of asctime() is asctime_r(). The Table 7–2_r” routines are supplied in the Solaris environment.

Table 7–2 Reentrant Functions

asctime_r(3c)

gethostbyname_r(3nsl)

getservbyname_r(3socket)

ctermid_r(3c)

gethostent_r(3nsl)

getservbyport_r(3socket)

ctime_r(3c)

getlogin_r(3c)

getservent_r(3socket)

fgetgrent_r(3c)

getnetbyaddr_r(3socket)

getspent_r(3c)

fgetpwent_r(3c)

getnetbyname_r(3socket)

getspnam_r(3c)

fgetspent_r(3c)

getnetent_r(3socket)

gmtime_r(3c)

gamma_r(3m)

getnetgrent_r(3c)

lgamma_r(3m)

getauclassent_r(3bsm)

getprotobyname_r(3socket)

localtime_r(3c)

getauclassnam_r(3bsm)

getprotobynumber_r(3socket)

nis_sperror_r(3nsl)

getauevent_r(3bsm)

getprotoent_r(3socket)

rand_r(3c)

getauevnam_r(3bsm)

getpwent_r(3c)

readdir_r(3c)

getauevnum_r(3bsm)

getpwnam_r(3c)

strtok_r(3c)

getgrent_r(3c)

getpwuid_r(3c)

tmpnam_r(3c)

getgrgid_r(3c)

getrpcbyname_r(3nsl)

ttyname_r(3c)

getgrnam_r(3c)

getrpcbynumber_r(3nsl)

 

gethostbyaddr_r(3nsl)

getrpcent_r(3nsl)

 

Async-Signal-Safe Functions in Solaris Threads

Functions that can safely be called from signal handlers are Async-Signal-Safe. The IEEE Std 1003.1–2004 (POSIX) standard defines Async-Signal-Safe functions, which are listed in Table 5–2. In addition to these standard Async-Signal-Safe functions, the following functions from the Solaris threads interface are also Async-Signal-Safe:

MT Safety Levels for Libraries

All routines that can potentially be called by a thread from a multithreaded program should be MT-Safe. Therefore, two or more activations of a routine must be able to correctly execute concurrently. So, every library interface that a multithreaded program uses must be MT-Safe.

Not all libraries are now MT-Safe. The commonly used libraries that are MT-Safe are listed in the following table. The libraries are accessed in the /usr/lib directory.

Table 7–3 Some MT-Safe Libraries

Library 

Comments 

libc

Interfaces that are not safe have thread-safe interfaces of the form *_r, often with different semantics.

libm

Math library that is compliant with System V Interface Definition, Edition 3, X/Open, and ANSI C

libmalloc

Space-efficient memory allocation library, see malloc(3MALLOC)

libmapmalloc

Alternative mmap-based memory allocation library, see mapmalloc(3MALLOC)

libnsl

The TLI interface, XDR, RPC clients and servers, netdir, netselect and getXXbyYY interfaces are not safe, but have thread-safe interfaces of the form getXXbyYY_r

libresolv

Domain name server library routines

libsocket

Socket library for making network connections

libX11

X11 Windows library routines

libCrun

C++ runtime shared objects for Sun C++ 5.0 compilers

libCstd

C++ standard library for Sun C++ 5.0 compilers

libiostream

Classic iostream library for Sun C++ 5.0 compilers

libC.so.5

C++ runtime and iostream library for Sun C++ 4.0 compilers

Unsafe Libraries

Routines in libraries that are not guaranteed to be MT-Safe can safely be called by multithreaded programs only when such calls are single threaded.