Doc. no.   N2298=07-0158
Date:        2007-06-21
Project:     Programming Language C++
Reply to:   Beman Dawes <bdawes at acm.org>
                Peter Dimov <pdimov at pdimov.com>
                Herb Sutter <hsutter at microsoft.com>

Thread-Safety in the Standard Library

Introduction

With the introduction of multi-threading into the C++ standard, the contract between standard library users and implementors needs to explicitly state the conditions under which standard library components are or are not thread-safe.

Rationale

The objective is to offer users of the standard library as much thread-safety as is possible without impacting performance or creating an illusion of safety where none exists.

Basic thread-safety guarantee

Guaranteeing thread-safety for non-shared objects has little or no impact on performance. It actually does deliver the promised safety. Thus this basic thread-safety is required of implementations.

Strong thread-safety guarantee

Guaranteeing thread-safety for shared objects would have a severe negative impact on performance. Furthermore, real safety often requires locking across several member function calls, so providing per function-call locking would create a illusion of safety that did in fact not exist. For these reasons, strong thread-safety for shared objects is not specified, and constraints are put on programs accordingly.

Meaning of thread-safety

Rather than try to define the term thread-safety, the proposed wording simple talks about data races and deadlocks. These terms will be defined in the core language portion of the standard, and/or are well-know terms of art that do not need to be further described in the library clauses.

Standard library components not given strong guarantee

Consideration was given to specifying rand function and the global locale objects on a per-thread basis. That is not proposed because it does not represent existing practice. Mac OS X, for example, does not support per-thread global locale objects.

Existing Practice

As far as is known, the proposed wording reflects existing practice in current implementations of the standard library.

Proposed Wording

Somewhere in [conforming] add a constraint on implementations:

Unless otherwise specified, access to different objects of types supplied by the standard library from different threads-of-execution shall not result in a data race or deadlock.

[Note: This means, for example, that implementations can't use a private static data member in a standard library class without synchronization because it could cause a data race or deadlock even in programs that do not share objects of that class between threads. --end note]

Unless otherwise specified, calls to standard library functions from different threads-of-execution shall not result in a data race or deadlock if the calls do not access non-const objects shared between the threads [constraints].

[Note: This means, for example, that implementations can't use a static object without synchronization for internal purposes because it could cause a data race or deadlock even in programs that do not explicitly share objects between threads. --end note]

Somewhere in [constraints] add a constraint on programs:

Unless otherwise specified, access to the same object of a standard library type from different threads-of-execution results in undefined behavior if any of the accesses are via a non-const member function of the object or non-const function parameter of any standard library function, and simultaneous access is not prevented by a standard library supplied locking mechanism ([Editor to supply reference]).

[Note: This lack of strong thread-safety guarantee means that sharing an object of a standard library type between threads without using a locking mechanism may result in a data race, deadlock, or other undesirable behavior. --end note]

Add to 19.3 Error numbers [errno] paragraph 1:

A separate errno value shall be provided for each thread-of-execution.

Change 20.7 Date and Time [date.time] as indicated:

The contents are the same as the Standard C library header <time.h> with the addition of the functions asctime_r, ctime_r, gmtime_r, and localtime_r as in the POSIX header <time.h>.229)

Functions asctime, ctime, gmtime, and localtime are not require to be thread-safe ([conforming]).

Change 21.4 Null-terminated sequence utilities [c.strings] as indicated:

The contents of these headers shall be the same as the Standard C Library headers <ctype.h>, <wctype.h>,
<string.h>, <wchar.h>, and <stdlib.h> and the C Unicode TR header <uchar.h>, respectively, with the following
modifications:

Header <cstring> includes the functions strerror_r and strtok_r as in the POSIX header <string.h>.

The strerror and strtok functions are not require to be thread-safe ([conforming]).

The headers shall not define the types char16_t, char32_t, and wchar_t (2.11).

Change 26.7 C Library [c.math] paragraph 5 and 6 as indicated:

The contents of these headers are the same as the Standard C library headers <math.h> and <stdlib.h> respectively,
with the following changes:

Header <cstdlib> includes the function rand_r as in the POSIX header <stdlib.h>.

The rand function has the semantics specified in the C standard, except that the implementation may specify that particular library functions may call rand. The rand function is not require to be thread-safe ([conforming]).

References

N1947, The Memory Model and the C++ Library, Non-Memory Actions etc., Nick Maclaren