Bug 49668

Summary: [C++0x] std::thread does not forward its args as rvalues
Product: gcc Reporter: Jonathan Wakely <redi>
Component: libstdc++Assignee: Jonathan Wakely <redi>
Status: RESOLVED FIXED    
Severity: normal Keywords: rejects-valid
Priority: P3    
Version: 4.7.0   
Target Milestone: 4.7.0   
Host: Target:
Build: Known to work:
Known to fail: Last reconfirmed: 2011-07-07 08:33:23
Attachments: do not use std::bind to implement std::thread

Description Jonathan Wakely 2011-07-07 08:30:54 UTC
Created attachment 24702 [details]
do not use std::bind to implement std::thread

#include <thread>

struct moveable
{
 moveable() = default;
 moveable(moveable&&) = default;
};

void f(moveable) { }

int main()
{
 std::thread t(f, moveable());
 t.join();
}

The problem is that std::thread uses std::bind internally and the call wrapper returned by std::bind forwards the bound args as lvalues (this is necessary because the call wrapper could be invoked multiple times, so the arguments cannot be moved from)

std::thread doesn't need most of the functionality of std::bind anyway, and using it actually makes this ill-formed because std::bind tries to act on the placeholder:

  void f(decltype(std::placeholders::_1));
  std::thread(t, std::placeholders::_1);
Comment 1 Jonathan Wakely 2011-07-07 08:33:23 UTC
The same problem exists for std::packaged_task and std::async

include <future>

struct moveable
{
 moveable() = default;
 moveable(moveable&&) = default;
};

void f(moveable) { }

int main()
{
 std::packaged_task<void(moveable)> p(f);
 p(moveable());
}
Comment 2 Jonathan Wakely 2011-07-07 11:02:01 UTC
Same problem for call_once too, basically everywhere that uses
 INVOKE( DECAY_COPY ( std::forward<Callable>(func)),
         DECAY_COPY (std::forward<Args>(args))...)

I'm going to split out the tuple<decay<F>::type, decay<Args>::type...> from thread::_Impl so it can be reused in <future> and <mutex>, as a really simple one-time use version of _Bind_result that doesn't support is_placeholder or is_bind_expression and forwards everything as rvalues, implementing the INVOKE expression above
Comment 3 Jonathan Wakely 2011-07-09 10:13:04 UTC
Author: redi
Date: Sat Jul  9 10:13:01 2011
New Revision: 176073

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=176073
Log:
2011-07-09  Jonathan Wakely  <jwakely.gcc@gmail.com>

	PR libstdc++/49668
	* include/std/functional (__bind_simple): Define.
	* include/std/future (_Task_setter): Parameterize by type of result
	pointer instead of state object.
	(_S_task_setter): Type deduction helper.
	(_Task_state): Use _S_task_setter and __bind_simple.
	(_Deferred_state, _Async_state): Store call wrapper directly not as
	std::function. Use _S_task_setter and __bind_simple.
	(_S_make_deferred_state, _S_make_async_state): Type deduction helpers.
	(async): Use new functions and __bind_simple.
	* include/std/mutex (call_once): Use __bind_simple.
	* include/std/thread (thread): Likewise. Remove unused headers.
	* src/thread.cc: Add header.
	* testsuite/30_threads/async/49668.cc: New.
	* testsuite/30_threads/call_once/49668.cc: New.
	* testsuite/30_threads/thread/cons/49668.cc: New.
	* testsuite/30_threads/thread/cons/moveable.cc: Remove unused bool.

Added:
    trunk/libstdc++-v3/testsuite/30_threads/async/49668.cc
    trunk/libstdc++-v3/testsuite/30_threads/call_once/49668.cc
    trunk/libstdc++-v3/testsuite/30_threads/packaged_task/49668.cc
    trunk/libstdc++-v3/testsuite/30_threads/thread/cons/49668.cc
Modified:
    trunk/libstdc++-v3/ChangeLog
    trunk/libstdc++-v3/include/std/functional
    trunk/libstdc++-v3/include/std/future
    trunk/libstdc++-v3/include/std/mutex
    trunk/libstdc++-v3/include/std/thread
    trunk/libstdc++-v3/src/thread.cc
    trunk/libstdc++-v3/testsuite/30_threads/thread/cons/moveable.cc
Comment 4 Jonathan Wakely 2011-07-09 10:14:29 UTC
fixed for 4.7.0

N.B. first reported in http://gcc.gnu.org/ml/libstdc++/2011-07/msg00006.html