Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are C/C++ fundamental types atomic?

Are C/C++ fundamental types, like int, double, etc., atomic, e.g. threadsafe?

Are they free from data races; that is, if one thread writes to an object of such a type while another thread reads from it, is the behavior well-defined?

If not, does it depend on the compiler or something else?

like image 950
Carmellose Avatar asked Feb 05 '16 14:02

Carmellose


People also ask

What are atomic types in C?

The type sig_atomic_t is always an integer data type, but which one it is, and how many bits it contains, may vary from machine to machine. Data Type: sig_atomic_t. This is an integer data type. Objects of this type are always accessed atomically. In practice, you can assume that int is atomic.

What is atomic operation C?

C was designed to run on a simple serial computer. But increasing numbers of machines have more than one CPU, and low-level code (the kind still written in C) has to work around this issue.

What is atomic data type?

An atomic datatype is a basic datatype such as a Boolean, string, integer, decimal, or date. To define custom atomic datatypes, add restrictions to an atomic datatype to limit the content.

Is assignment atomic in C?

What is an atomic operation in C? Neither of them are, although it is quite rare for the assignment to not be atomic. You have to document the core and compiler to get a useful answer.


2 Answers

No, fundamental data types (e.g., int, double) are not atomic, see std::atomic.

Instead you can use std::atomic<int> or std::atomic<double>.

Note: std::atomic was introduced with C++11 and my understanding is that prior to C++11, the C++ standard didn't recognize the existence of multithreading at all.


As pointed out by @Josh, std::atomic_flag is an atomic boolean type. It is guaranteed to be lock-free, unlike the std::atomic specializations.


The quoted documentation is from: http://open-std.org/JTC1/SC22/WG21/docs/papers/2015/n4567.pdf. I'm pretty sure the standard is not free and therefore this isn't the final/official version.

1.10 Multi-threaded executions and data races

  1. Two expression evaluations conflict if one of them modifies a memory location (1.7) and the other one reads or modifies the same memory location.
  2. The library defines a number of atomic operations (Clause 29) and operations on mutexes (Clause 30) that are specially identified as synchronization operations. These operations play a special role in making assignments in one thread visible to another. A synchronization operation on one or more memory locations is either a consume operation, an acquire operation, a release operation, or both an acquire and release operation. A synchronization operation without an associated memory location is a fence and can be either an acquire fence, a release fence, or both an acquire and release fence. In addition, there are relaxed atomic operations, which are not synchronization operations, and atomic read-modify-write operations, which have special characteristics.


  1. Two actions are potentially concurrent if
    (23.1) — they are performed by different threads, or
    (23.2) — they are unsequenced, and at least one is performed by a signal handler.
    The execution of a program contains a data race if it contains two potentially concurrent conflicting actions, at least one of which is not atomic, and neither happens before the other, except for the special case for signal handlers described below. Any such data race results in undefined behavior.

29.5 Atomic types

  1. There shall be explicit specializations of the atomic template for the integral types ``char, signed char, unsigned char, short, unsigned short, int, unsigned int, long, unsigned long, long long, unsigned long long, char16_t, char32_t, wchar_t, and any other types needed by the typedefs in the header <cstdint>. For each integral type integral, the specialization atomic<integral> provides additional atomic operations appropriate to integral types. There shall be a specialization atomic<bool> which provides the general atomic operations as specified in 29.6.1..


  1. There shall be pointer partial specializations of the atomic class template. These specializations shall have standard layout, trivial default constructors, and trivial destructors. They shall each support aggregate initialization syntax.

29.7 Flag type and operations

  1. Operations on an object of type atomic_flag shall be lock-free. [ Note: Hence the operations should also be address-free. No other type requires lock-free operations, so the atomic_flag type is the minimum hardware-implemented type needed to conform to this International standard. The remaining types can be emulated with atomic_flag, though with less than ideal properties. — end note ]
like image 112
James Adkison Avatar answered Oct 06 '22 00:10

James Adkison


Since C is also (currently) mentioned in the question despite not being in the tags, the C Standard states:

5.1.2.3 Program execution

...

When the processing of the abstract machine is interrupted by receipt of a signal, the values of objects that are neither lock-free atomic objects nor of type volatile sig_atomic_t are unspecified, as is the state of the floating-point environment. The value of any object modified by the handler that is neither a lock-free atomic object nor of type volatile sig_atomic_t becomes indeterminate when the handler exits, as does the state of the floating-point environment if it is modified by the handler and not restored to its original state.

and

5.1.2.4 Multi-threaded executions and data races

...

Two expression evaluations conflict if one of them modifies a memory location and the other one reads or modifies the same memory location.

[several pages of standards - some paragraphs explicitly addressing atomic types]

The execution of a program contains a data race if it contains two conflicting actions in different threads, at least one of which is not atomic, and neither happens before the other. Any such data race results in undefined behavior.

Note that values are "indeterminate" if a signal interrupts processing, and simultaneous access to types that are not explicitly atomic is undefined behavior.

like image 26
Andrew Henle Avatar answered Oct 06 '22 02:10

Andrew Henle