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 constructorSection: 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 other active issues in [thread.thread.constr].
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 withdecay<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 eachTi
inArgs
shall beCopyConstructible
if an lvalue and otherwiseMoveConstructible
.INVOKE(f, w1, w2, ..., wN)
(22.10.4 [func.require]) shall be a valid expression for some valuesw1, w2, ... , wN,
whereN == sizeof...(Args)
.-5- Effects: Constructs an object of type
thread
and executesINVOKE(f, t1, t2, ..., tN)
in a new thread of execution, wheret1, t2, ..., tN
are the values inargs...
. Constructs the following objects in memory which is accessible to a new thread of execution as if:typename decay<F>::type g(std::forward<F>(f)); tuple<typename decay<Args>::type...> w(std::forward<Args>(args)...);The new thread of execution executes
INVOKE(g, wi...)
where thewi...
refers to the elements stored in thetuple w
. Any return value fromg
is ignored. Iff
terminates with an uncaught exception,std::terminate()
shall be called. If the evaluation ofINVOKE(g, wi...)
terminates with an uncaught exception,std::terminate()
shall be called [Note:std::terminate()
could be called before enteringg
. -- end note]. Any exception thrown before the evaluation ofINVOKE
has started shall be catchable in the calling thread.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> explicit 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 eachTi
inArgs
shall beCopyConstructible
if an lvalue and otherwiseMoveConstructible
.INVOKE(f, w1, w2, ..., wN)
(22.10.4 [func.require]) shall be a valid expression for some valuesw1, w2, ... , wN,
whereN == sizeof...(Args)
.-5- Effects: Constructs an object of type
thread
and executesINVOKE(f, t1, t2, ..., tN)
in a new thread of execution, wheret1, t2, ..., tN
are the values inargs...
. Constructs the following objects:typename decay<F>::type g(std::forward<F>(f)); tuple<typename decay<Args>::type...> w(std::forward<Args>(args)...);and executes
INVOKE(g, wi...)
in a new thread of execution. These objects shall be destroyed when the new thread of execution completes. Any return value fromg
is ignored. Iff
terminates with an uncaught exception,std::terminate()
shall be called. If the evaluation ofINVOKE(g, wi...)
terminates with an uncaught exception,std::terminate()
shall be called [Note:std::terminate()
could be called before enteringg
. -- end note]. Any exception thrown before the evaluation ofINVOKE
has started shall be catchable in the calling thread.-6- Synchronization: The invocation of the constructor happens before the invocation of
f
g
.
[ 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> explicit 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:
Given a function as follows:
template<typename T> typename decay<T>::type decay_copy(T&& v) { return std::forward<T>(v); }-4- Requires:
F
and eachTi
inArgs
shall beCopyConstructible
if an lvalue and otherwise satisfy theMoveConstructible
requirements.INVOKE(f, w1, w2, ..., wN)
(22.10.4 [func.require]) shall be a valid expression for some valuesw1, w2, ... , wN,
whereN == sizeof...(Args)
.INVOKE(decay_copy(std::forward<F>(f)), decay_copy(std::forward<Args>(args))...)
(22.10.4 [func.require]) shall be a valid expression.-5- Effects: Constructs an object of type
thread
and executesINVOKE(f, t1, t2, ..., tN)
in a new thread of execution, wheret1, t2, ..., tN
are the values inargs...
. Any return value fromf
is ignored. Iff
terminates with an uncaught exception,std::terminate()
shall be called. The new thread of execution executesINVOKE(decay_copy(std::forward<F>(f)), decay_copy(std::forward<Args>(args))...)
with the calls todecay_copy()
being evaluated in the constructing thread. Any return value from this invocation is ignored. [Note: this implies any exceptions not thrown from the invocation of the copy off
will be thrown in the constructing thread, not the new thread. — end note]. If the invocation ofINVOKE(decay_copy(std::forward<F>(f)), decay_copy(std::forward<Args>(args))...)
terminates with an uncaught exception,std::terminate
shall be called.-6- Synchronization: The invocation of the constructor happens before the invocation of the copy of
f
.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4