Title
std::thread's constructor needs to be able to report general memory allocation failures
Status
new
Section
[thread.thread.constr][thread.jthread.cons]
Submitter
Billy O'Neal III

Created on 2020-08-14.00:00:00 last changed 1 month ago

Messages

Date: 2020-08-21.20:17:54

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 [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 [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 [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 [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.

Date: 2020-08-15.00:00:00

[ 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 ...".

Date: 2020-08-17.17:57:40

(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.

History
Date User Action Args
2020-08-21 20:17:54adminsetmessages: + msg11444
2020-08-15 21:03:05adminsetmessages: + msg11437
2020-08-14 00:00:00admincreate