Namespaces
Variants
Views
Actions

Difference between revisions of "cpp/language/memory model"

From cppreference.com
< cpp‎ | language
(Forward progress (including P0296R2 and P0299R1))
(Removed the [intro.multithread] content, they are now in a new page.)
 
(24 intermediate revisions by 15 users not shown)
Line 6: Line 6:
  
 
===Byte===
 
===Byte===
A ''byte'' is the smallest addressable unit of memory. It is defined as a contiguous sequence of bits, large enough to hold {{rev inl|since=c++14|the value of any {{tt|UTF-8}} code unit (256 distinct values) and of }}any member of the ''basic execution character set'' ({{rlp|translation_phases|the 96 characters}} that are required to be single-byte). Similar to C, C++ supports bytes of sizes 8 bits and greater.
+
A ''byte'' is the smallest addressable unit of memory. It is defined as a contiguous sequence of bits, large enough to hold
 +
* the value of any {{tt|UTF-8}} code unit (256 distinct values) and of
 +
{{rrev multi
 +
|rev1=
 +
* any member of the {{rlpsd|charset#Basic execution character set}}.
 +
|since2=c++23|rev2=
 +
* the ordinary literal encoding of any element of the {{rlpsd|charset#Basic literal character set}}.
 +
}}
 +
Similar to C, C++ supports bytes of sizes 8 bits and greater.
  
The {{rlp|types}} {{c|char}}, {{c|unsigned char}}, and {{c|signed char}} use one byte for both storage and {{rlp|object|value representation}}. The number of bits in a byte is accessible as {{lc|CHAR_BIT}} or {{c|std::numeric_limits<unsigned char>::digits}}.
+
The {{rlp|types}} {{c/core|char}}, {{c/core|unsigned char}}, and {{c/core|signed char}} use one byte for both storage and {{rlp|object|value representation}}. The number of bits in a byte is accessible as {{lc|CHAR_BIT}} or {{c|std::numeric_limits<unsigned char>::digits}}.
  
 
===Memory location===
 
===Memory location===
 
A ''memory location'' is  
 
A ''memory location'' is  
* an object of {{rlp|type|scalar type}} (arithmetic type, pointer type, enumeration type, or std::nullptr_t)
+
* an object of {{rlp|type|scalar type}}, or
* or the largest contiguous sequence of {{rlp|bit field}}s of non-zero length
+
* the largest contiguous sequence of {{rlp|bit field|bit-fields}} of non-zero length.
 +
 
 +
Note: Various features of the language, such as {{rlp|reference|references}} and {{rlp|virtual|virtual functions}}, might involve additional memory locations that are not accessible to programs but are managed by the implementation.
  
 
{{source|
 
{{source|
struct S {
+
struct S
 +
{
 
     char a;    // memory location #1
 
     char a;    // memory location #1
 
     int b : 5;  // memory location #2
 
     int b : 5;  // memory location #2
Line 22: Line 33:
 
           : 0,
 
           : 0,
 
         d : 8;  // memory location #3
 
         d : 8;  // memory location #3
     struct {
+
     struct
 +
    {
 
         int ee : 8; // memory location #4
 
         int ee : 8; // memory location #4
 
     } e;
 
     } e;
} obj; // The object 'obj' consists of 4 separate memory locations
+
} obj; // The object “obj” consists of 4 separate memory locations
 
}}
 
}}
 
===Threads and data races===
 
A thread of execution is a flow of control within a program that begins with the invocation of a top-level function by {{lc|std::thread::thread}}, {{lc|std::async}}, or other means.
 
 
Any thread can potentially access any object in the program (objects with automatic and thread-local {{rlp|storage duration}} may still be accessed by another thread through a pointer or by reference).
 
 
Different threads of execution are always allowed to access (read and modify) different ''memory locations'' concurrently, with no interference and no synchronization requirements.
 
 
When an {{rlp|eval_order|evaluation}} of an expression writes to a memory location and another evaluation reads or modifies the same memory location, the expressions are said to ''conflict''. A program that has two conflicting evaluations has a ''data race'' unless either
 
* both conflicting evaluations are atomic operations (see {{lc|std::atomic}})
 
* one of the conflicting evaluations ''happens-before'' another (see {{lc|std::memory_order}})
 
 
If a data race occurs, the behavior of the program is undefined.
 
 
(in particular, release of a {{lc|std::mutex}} is ''synchronized-with'', and therefore, ''happens-before'' acquisition of the same mutex by another thread, which makes it possible to use mutex locks to guard against data races) {{todo|small example or two}}
 
 
===Memory order===
 
When a thread reads a value from a memory location, it may see the initial value, the value written in the same thread, or the value written in another thread. See {{lc|std::memory_order}} for details on the order in which writes made from threads become visible to other threads.
 
 
===Forward progress===
 
 
====Obstruction freedom====
 
When only one thread that is not blocked in a standard library function executes an [[cpp/atomic|atomic function]] that is lock-free, that execution is guaranteed to complete (all standard library lock-free operations are [[enwiki:Non-blocking_algorithm#Obstruction-freedom|obstruction-free]])
 
 
====Lock freedom====
 
When one or more lock-free atomic functions run concurrently, at least one of them is guaranteed to complete (all standard library lock-free operations are [[enwiki:Non-blocking_algorithm#Lock-freedom|lock-free]] -- it is the job of the implementation to ensure they cannot be live-locked indefinitely by other threads, such as by continuously stealing the cache line)
 
 
====Progress guarantee====
 
In a valid C++ program, every thread eventually does one of the following:
 
* terminate
 
* makes a call to an I/O library function
 
* reads or modifies a {{rlp|cv|volatile}} object
 
* performs an atomic operation or a synchronization operation
 
 
No thread of execution can execute forever without performing any of these observable behaviors.
 
 
Note that it means that a program with endless recursion or endless loop (whether implemented as a {{rlp|for|for-statement}} or by looping {{rlp|goto}} or otherwise) has {{rlp|ub|undefined behavior}}. This allows the compilers to remove all loops that have no observable behavior, without having to prove that they would eventually terminate.
 
 
A thread is said to ''make progress'' if it performs one of the execution steps above (I/O, volatile, atomic, or synchronization), blocks in a standard library function, or calls an atomic lock-free function that does not complete because of a non-blocked concurrent thread.
 
 
{{rev begin}}
 
{{rev|since=c++17|
 
====Concurrent forward progress====
 
If a thread offers ''concurrent forward progress guarantee'', it will  ''make progress'' (as defined above) in finite amount of time, for as long as it has not terminated, regardless of whether other threads (if any) are making progress.
 
 
The standard encourages, but doesn't require that the main thread and the threads started by {{lc|std::thread}} offer concurrent forward progress guarantee.
 
 
====Parallel forward progress====
 
If a thread offers ''parallel forward progress guarantee'', the implementation is not required
 
to ensure that the thread will eventually make progress if it has not yet executed any execution step (I/O, volatile, atomic, or synchronization), but once this thread has executed a step, it provides ''concurrent forward progress'' guarantees (this rule describes a thread in a thread pool that executes tasks in arbitrary order)
 
 
====Weakly parallel forward progress====
 
If a thread offers ''weakly parallel forward progress guarantee'', it does not guarantee to eventually make progress, regardless of whether other threads make progress or not.
 
 
Such threads can still me guaranteed to make progress by blocking with forward progress guarantee delegation: if a thread P blocks in this manner on the completion of a set of threads S, then at last one thread in S will offer a forward progress guarantee that is same or stronger than P. Once that thread completes, another thread in S will be similarly strengthened. Once the set is empty, P will unblock.
 
 
The [[cpp/algorithm|parallel algorithms]] from the C++ standard library block with forward progress delegation on the completion of an unspecified set of library-managed threads.
 
}}
 
{{rev end}}
 
  
 
===See also===
 
===See also===
 
{{dsc begin}}
 
{{dsc begin}}
{{dsc see c | c/language/memory_model | Memory model}}
+
{{dsc see c|c/language/memory model|Memory model|nomono=true}}
 
{{dsc end}}
 
{{dsc end}}
 +
 +
{{langlinks|es|ja|ru|zh}}

Latest revision as of 22:47, 21 April 2024

 
 
C++ language
General topics
Flow control
Conditional execution statements
if
Iteration statements (loops)
for
range-for (C++11)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications (until C++17*)
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
explicit (C++11)
static

Special member functions
Templates
Miscellaneous
 
 

Defines the semantics of computer memory storage for the purpose of the C++ abstract machine.

The memory available to a C++ program is one or more contiguous sequences of bytes. Each byte in memory has a unique address.

[edit] Byte

A byte is the smallest addressable unit of memory. It is defined as a contiguous sequence of bits, large enough to hold

  • the value of any UTF-8 code unit (256 distinct values) and of
(until C++23)
(since C++23)

Similar to C, C++ supports bytes of sizes 8 bits and greater.

The types char, unsigned char, and signed char use one byte for both storage and value representation. The number of bits in a byte is accessible as CHAR_BIT or std::numeric_limits<unsigned char>::digits.

[edit] Memory location

A memory location is

Note: Various features of the language, such as references and virtual functions, might involve additional memory locations that are not accessible to programs but are managed by the implementation.

struct S
{
    char a;     // memory location #1
    int b : 5;  // memory location #2
    int c : 11, // memory location #2 (continued)
          : 0,
        d : 8;  // memory location #3
    struct
    {
        int ee : 8; // memory location #4
    } e;
} obj; // The object “obj” consists of 4 separate memory locations

[edit] See also

C documentation for Memory model