Movatterモバイル変換


[0]ホーム

URL:


cppreference.com
Namespaces
Variants
    Actions

      Multi-threaded executions and data races(since C++11)

      From cppreference.com
      <cpp‎ |language
       
       
      C++ language
      General topics
      Flow control
      Conditional execution statements
      Iteration statements (loops)
      Jump statements
      Functions
      Function declaration
      Lambda function expression
      inline specifier
      Dynamic exception specifications(until C++17*)
      noexcept specifier(C++11)
      Exceptions
      Namespaces
      Types
      Specifiers
      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
      Special member functions
      Templates
      Miscellaneous
       
       

      Athread of execution is a flow of control within a program that begins with the invocation of a specific top-level function (bystd::thread,std::async,std::jthread(since C++20) or other means), and recursively including every function invocation subsequently executed by the thread.

      • When one thread creates another, the initial call to the top-level function of the new thread is executed by the new thread, not by the creating thread.

      Any thread can potentially access any object and function in the program:

      • Objects with automatic and thread-localstorage duration may still be accessed by another thread through a pointer or by reference.
      • Under ahosted implementation, a C++ program can have more than one thread running concurrently. The execution of each thread proceeds as defined by the rest of this page. The execution of the entire program consists of an execution of all of its threads.
      • Under afreestanding implementation, it is implementation-defined whether a program can have more than one thread of execution.

      For asignal handler that is not executed as a result of a call tostd::raise, it is unspecified which thread of execution contains the signal handler invocation.

      Contents

      [edit]Data races

      Different threads of execution are always allowed to access (read and modify) differentmemory locations concurrently, with no interference and no synchronization requirements.

      Two expressionevaluationsconflict if one of them modifies a memory location or starts/ends the lifetime of an object in a memory location, and the other one reads or modifies the same memory location or starts/ends the lifetime of an object occupying storage that overlaps with the memory location.

      A program that has two conflicting evaluations has adata race unless

      • both evaluations execute on the same thread or in the samesignal handler, or
      • both conflicting evaluations are atomic operations (seestd::atomic), or
      • one of the conflicting evaluationshappens-before another (seestd::memory_order).

      If a data race occurs, the behavior of the program is undefined.

      (In particular, release of astd::mutex issynchronized-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.)

      int cnt=0;auto f=[&]{ cnt++;};std::thread t1{f}, t2{f}, t3{f};// undefined behavior
      std::atomic<int> cnt{0};auto f=[&]{ cnt++;};std::thread t1{f}, t2{f}, t3{f};// OK

      [edit]Container data races

      Allcontainers in the standard library exceptstd::vector<bool> guarantee that concurrent modifications on contents of the contained object in different elements in the same container will never result in data races.

      std::vector<int> vec={1,2,3,4};auto f=[&](int index){ vec[index]=5;};std::thread t1{f,0}, t2{f,1};// OKstd::thread t3{f,2}, t4{f,2};// undefined behavior
      std::vector<bool> vec={false,false};auto f=[&](int index){ vec[index]=true;};std::thread t1{f,0}, t2{f,1};// undefined behavior

      [edit]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. Seestd::memory_order for details on the order in which writes made from threads become visible to other threads.

      [edit]Forward progress

      [edit]Obstruction freedom

      When only one thread that is not blocked in a standard library function executes anatomic function that is lock-free, that execution is guaranteed to complete (all standard library lock-free operations areobstruction-free).

      [edit]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 arelock-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).

      [edit]Progress guarantee

      In a valid C++ program, every thread eventually does one of the following:

      • Terminates.
      • Invokesstd::this_thread::yield.
      • Makes a call to an library I/O function.
      • Performs an access through avolatile glvalue.
      • Performs an atomic operation or a synchronization operation.
      • Continues execution of a trivial infinite loop (see below).

      A thread is said tomake progress if it performs one of the execution steps above, blocks in a standard library function, or calls an atomic lock-free function that does not complete because of a non-blocked concurrent thread.

      This allows the compilers to remove, merge and reorder all loops that have no observable behavior, without having to prove that they would eventually terminate because it can assume that no thread of execution can execute forever without performing any of these observable behaviors. An affordance is made for trivial infinite loops, which cannot be removed nor reordered.

      [edit]Trivial infinite loops

      Atrivially empty iteration statement is an iteration statement matching one of the following forms:

      while (condition) ; (1)
      while (condition) { } (2)
      do ; while (condition) ; (3)
      do { } while (condition) ; (4)
      for (init-statement condition (optional); ) ; (5)
      for (init-statement condition (optional); ) { } (6)
      1) Awhile statement whose loop body is an empty simple statement.
      2) Awhile statement whose loop body is an empty compound statement.
      3) Ado-while statement whose loop body is an empty simple statement.
      4) Ado-while statement whose loop body is an empty compound statement.
      5) Afor statement whose loop body is an empty simple statement, thefor statement does not have aniteration-expression.
      6) Afor statement whose loop body is an empty compound statement, thefor statement does not have aniteration-expression.

      Thecontrolling expression of a trivially empty iteration statement is:

      1-4)condition.
      5,6)condition if present, otherwisetrue.

      Atrivial infinite loop is a trivially empty iteration statement for which the converted controlling expression is aconstant expression, whenmanifestly constant-evaluated, and evaluates totrue.

      The loop body of a trivial infinite loop is replaced with a call to the functionstd::this_thread::yield. It is implementation-defined whether this replacement occurs onfreestanding implementations.

      for(;;);// trivial infinite loop, well defined as of P2809for(;;){int x;}// undefined behavior

      Concurrent forward progress

      If a thread offersconcurrent forward progress guarantee, it willmake 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 bystd::threadandstd::jthread(since C++20) offer concurrent forward progress guarantee.

      Parallel forward progress

      If a thread offersparallel forward progress guarantee, the implementation is not requiredto 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 providesconcurrent 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 offersweakly 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 be guaranteed to make progress by blocking with forward progress guarantee delegation: if a threadP blocks in this manner on the completion of a set of threadsS, then at least one thread inS will offer a forward progress guarantee that is same or stronger thanP. Once that thread completes, another thread inS will be similarly strengthened. Once the set is empty,P will unblock.

      Theparallel algorithms from the C++ standard library block with forward progress delegation on the completion of an unspecified set of library-managed threads.

      (since C++17)

      [edit]Defect reports

      The following behavior-changing defect reports were applied retroactively to previously published C++ standards.

      DRApplied toBehavior as publishedCorrect behavior
      CWG 1953C++11two expression evaluations that start/end the lifetimes
      of objects with overlapping storages did not conflict
      they conflict
      LWG 2200C++11it was unclear whether the container data race
      requirement only applies to sequence containers
      applies to all containers
      P2809R3C++11the behavior of executing “trivial”[1]
      infinite loops was undefined
      properly defines “trivial infinite loops”
      and made the behavior well-defined
      1. “Trivial” here means executing the infinite loop never makes any progress.
      Retrieved from "https://en.cppreference.com/mwiki/index.php?title=cpp/language/multithread&oldid=179724"

      [8]ページ先頭

      ©2009-2025 Movatter.jp