This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.

3475. std::thread's constructor needs to be able to report general memory allocation failures

Section: 32.4.3.3 [thread.thread.constr], 32.4.4.2 [thread.jthread.cons] Status: New Submitter: Billy O'Neal III Opened: 2020-08-14 Last modified: 2020-09-06

Priority: 3

View all other issues in [thread.thread.constr].

View all issues with New status.

Discussion:

(j)thread's constructor needs to decay-copy the supplied parameters and callable over to the started thread through an operating system API that generally only accepts a single void*. The MSVC++ and libc++ implementations do this by putting the parameters in a std::tuple allocated from the heap, passing a pointer to that tuple through the operating system API, and leaving ownership of the parameters to the other thread.

It might be theoretically possible to introduce an additional copy and synchronization where the starting thread blocks for the started thread to make a move constructed copy of that tuple from the parameters, but that would introduce unreasonable synchronization overhead since the starting thread would have to block for all TLS initializers and similar in the started thread.

It is technically possible to implement the current design by transforming this allocation failure into resource_unavailable_try_again, but the description for this error in the standard is that some thread-based limitation has been reached, not a general memory limit, so that doesn't seem to meet the spirit of the requirement.

[2020-08-21; Issue processing telecon: set priority to 3]

Jonathan: I prefer Option A, but I think we need something like: "any exceptions thrown by the decay-copy calls, or ...".

Proposed resolution:

This wording is relative to N4861.

[Drafting Note: Two mutually exclusive options are prepared, depicted below by Option A and Option B, respectively.]

Option A: The memory allocation failure results in bad_alloc.

  1. Modify 32.4.3.3 [thread.thread.constr] as indicated:

    template<class F, class... Args> explicit thread(F&& f, Args&&... args);
    

    -3- Constraints: […]

    […]

    -8- Postconditions: get_id() != id(). *this represents the newly started thread.

    -9- Throws: bad_alloc if memory to transfer parameters to the new thread cannot be obtained. system_error if unable to start the new thread.

    -10- Error conditions:

    1. (10.1) — resource_unavailable_try_again — the system lacked the necessary resources to create another thread, or the system-imposed limit on the number of threads in a process would be exceeded.

  2. Modify 32.4.4.2 [thread.jthread.cons] as indicated:

    template<class F, class... Args> explicit jthread(F&& f, Args&&... args);
    

    -3- Constraints: […]

    […]

    -8- Postconditions: get_id() != id() is true and ssource.stop_possible() is true and *this represents the newly started thread. [Note: The calling thread can make a stop request only once, because it cannot replace this stop token. — end note]

    -9- Throws: bad_alloc if memory to transfer parameters to the new thread cannot be obtained. system_error if unable to start the new thread.

    -10- Error conditions:

    1. (10.1) — resource_unavailable_try_again — the system lacked the necessary resources to create another thread, or the system-imposed limit on the number of threads in a process would be exceeded.

Option B: The memory allocation failure results in a system_error with the error condition out_of_memory.

  1. Modify 32.4.3.3 [thread.thread.constr] as indicated:

    template<class F, class... Args> explicit thread(F&& f, Args&&... args);
    

    -3- Constraints: […]

    […]

    -8- Postconditions: get_id() != id(). *this represents the newly started thread.

    -9- Throws: system_error if unable to start the new thread.

    -10- Error conditions:

    1. (10.?) — not_enough_memory — the system lacked memory resources to transfer parameters to the new thread.

    2. (10.1) — resource_unavailable_try_again — the system lacked the necessary resources to create another thread, or the system-imposed limit on the number of threads in a process would be exceeded.

  2. Modify 32.4.4.2 [thread.jthread.cons] as indicated:

    template<class F, class... Args> explicit jthread(F&& f, Args&&... args);
    

    -3- Constraints: […]

    […]

    -8- Postconditions: get_id() != id() is true and ssource.stop_possible() is true and *this represents the newly started thread. [Note: The calling thread can make a stop request only once, because it cannot replace this stop token. — end note]

    -9- Throws: system_error if unable to start the new thread.

    -10- Error conditions:

    1. (10.?) — not_enough_memory — the system lacked memory resources to transfer parameters to the new thread.

    2. (10.1) — resource_unavailable_try_again — the system lacked the necessary resources to create another thread, or the system-imposed limit on the number of threads in a process would be exceeded.