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

929. Thread constructor

Section: 32.4.3.3 [thread.thread.constr] Status: C++11 Submitter: Anthony Williams Opened: 2008-10-23 Last modified: 2016-01-28

Priority: Not Prioritized

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

View all issues with C++11 status.

Discussion:

Addresses UK 323

The thread constructor for starting a new thread with a function and arguments is overly constrained by the signature requiring rvalue references for func and args and the CopyConstructible requirements for the elements of args. The use of an rvalue reference for the function restricts the potential use of a plain function name, since the type of the bound parameter will be deduced to be a function reference and decay to pointer-to-function will not happen. This therefore complicates the implementation in order to handle a simple case. Furthermore, the use of rvalue references for args prevents the array to pointer decay. Since arrays are not CopyConstructible or even MoveConstructible, this essentially prevents the passing of arrays as parameters. In particular it prevents the passing of string literals. Consequently a simple case such as

void f(const char*);
std::thread t(f,"hello");

is ill-formed since the type of the string literal is const char[6].

By changing the signature to take all parameters by value we can eliminate the CopyConstructible requirement and permit the use of arrays, as the parameter passing semantics will cause the necessary array-to-pointer decay. They will also cause the function name to decay to a pointer to function and allow the implementation to handle functions and function objects identically.

The new signature of the thread constructor for a function and arguments is thus:

template<typename F,typename... Args>
thread(F,Args... args);

Since the parameter pack Args can be empty, the single-parameter constructor that takes just a function by value is now redundant.

[ Howard adds: ]

I agree with everything Anthony says in this issue. However I believe we can optimize in such a way as to get the pass-by-value behavior with the pass-by-rvalue-ref performance. The performance difference is that the latter removes a move when passing in an lvalue.

This circumstance is very analogous to make_pair (22.3 [pairs]) where we started with passing by const reference, changed to pass by value to get pointer decay, and then changed to pass by rvalue reference, but modified with decay<T> to retain the pass-by-value behavior. If we were to apply the same solution here it would look like:

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

-4- Requires: F and each Ti in Args shall be CopyConstructible if an lvalue and otherwise MoveConstructible. INVOKE(f, w1, w2, ..., wN) (22.10.4 [func.require]) shall be a valid expression for some values w1, w2, ... , wN, where N == sizeof...(Args).

-5- Effects: Constructs an object of type thread and executes INVOKE(f, t1, t2, ..., tN) in a new thread of execution, where t1, t2, ..., tN are the values in args....



Any return value from g is ignored. If f terminates with an uncaught exception, std::terminate() shall be called.

Text referring to when terminate() is called was contributed by Ganesh.

[ Batavia (2009-05): ]

We agree with the proposed resolution, but would like the final sentence to be reworded since "catchable" is not a term of art (and is used nowhere else).

[ 2009-07 Frankfurt: ]

This is linked to N2901.

Howard to open a separate issue to remove (1176(i)).

In Frankfurt there is no consensus for removing the variadic constructor.

[ 2009-10 Santa Cruz: ]

We want to move forward with this issue. If we later take it out via 1176(i) then that's ok too. Needs small group to improve wording.

[ 2009-10 Santa Cruz: ]

Stefanus provided revised wording. Moved to Review Here is the original wording:

Modify the class definition of std::thread in 32.4.3 [thread.thread.class] to remove the following signature:

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

Modify 32.4.3.3 [thread.thread.constr] to replace the constructors prior to paragraph 4 with the single constructor as above. Replace paragraph 4 - 6 with the following:

-4- Requires: F and each Ti in Args shall be CopyConstructible if an lvalue and otherwise MoveConstructible. INVOKE(f, w1, w2, ..., wN) (22.10.4 [func.require]) shall be a valid expression for some values w1, w2, ... , wN, where N == sizeof...(Args).

-5- Effects: Constructs an object of type thread and executes INVOKE(f, t1, t2, ..., tN) in a new thread of execution, where t1, t2, ..., tN are the values in args....



Any return value from g is ignored. If f terminates with an uncaught exception, std::terminate() shall be called.

-6- Synchronization: The invocation of the constructor happens before the invocation of f .

[ 2010-01-19 Moved to Tentatively Ready after 5 positive votes on c++std-lib. ]

Proposed resolution:

Modify the class definition of std::thread in 32.4.3 [thread.thread.class] to remove the following signature:

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

Modify 32.4.3.3 [thread.thread.constr] to replace the constructors prior to paragraph 4 with the single constructor as above. Replace paragraph 4 - 6 with the following:

-4- Requires: F and each Ti in Args shall be CopyConstructible if an lvalue and otherwise MoveConstructible . INVOKE(f, w1, w2, ..., wN) (22.10.4 [func.require]) shall be a valid expression for some values w1, w2, ... , wN, where N == sizeof...(Args).

-5- Effects: Constructs an object of type thread and executes INVOKE(f, t1, t2, ..., tN) in a new thread of execution, where t1, t2, ..., tN are the values in args.... Any return value from f is ignored. If f terminates with an uncaught exception, std::terminate() shall be called.

-6- Synchronization: The invocation of the constructor happens before the invocation of f.