template<typename _Fn, typename _Alloc, typename _Signature>
class _Task_state;
- template<typename _BoundFn>
- static std::shared_ptr<_State_base>
- _S_make_deferred_state(_BoundFn&& __fn);
-
- template<typename _BoundFn>
- static std::shared_ptr<_State_base>
- _S_make_async_state(_BoundFn&& __fn);
-
template<typename _Res_ptr, typename _Fn,
typename _Res = typename _Res_ptr::element_type::result_type>
struct _Task_setter;
: public __future_base::_State_base
{
public:
- explicit
- _Deferred_state(_BoundFn&& __fn)
- : _M_result(new _Result<_Res>()), _M_fn(std::move(__fn))
- { }
+ template<typename... _Args>
+ explicit
+ _Deferred_state(_Args&&... __args)
+ : _M_result(new _Result<_Res>()),
+ _M_fn{{std::forward<_Args>(__args)...}}
+ { }
private:
typedef __future_base::_Ptr<_Result<_Res>> _Ptr_type;
: public __future_base::_Async_state_commonV2
{
public:
- explicit
- _Async_state_impl(_BoundFn&& __fn)
- : _M_result(new _Result<_Res>()), _M_fn(std::move(__fn))
- {
- _M_thread = std::thread{ [this] {
- __try
- {
- _M_set_result(_S_task_setter(_M_result, _M_fn));
- }
- __catch (const __cxxabiv1::__forced_unwind&)
- {
- // make the shared state ready on thread cancellation
- if (static_cast<bool>(_M_result))
- this->_M_break_promise(std::move(_M_result));
- __throw_exception_again;
- }
- } };
- }
+ template<typename... _Args>
+ explicit
+ _Async_state_impl(_Args&&... __args)
+ : _M_result(new _Result<_Res>()),
+ _M_fn{{std::forward<_Args>(__args)...}}
+ {
+ _M_thread = std::thread{&_Async_state_impl::_M_run, this};
+ }
// Must not destroy _M_result and _M_fn until the thread finishes.
// Call join() directly rather than through _M_join() because no other
// thread can be referring to this state if it is being destroyed.
- ~_Async_state_impl() { if (_M_thread.joinable()) _M_thread.join(); }
+ ~_Async_state_impl()
+ {
+ if (_M_thread.joinable())
+ _M_thread.join();
+ }
private:
+ void
+ _M_run()
+ {
+ __try
+ {
+ _M_set_result(_S_task_setter(_M_result, _M_fn));
+ }
+ __catch (const __cxxabiv1::__forced_unwind&)
+ {
+ // make the shared state ready on thread cancellation
+ if (static_cast<bool>(_M_result))
+ this->_M_break_promise(std::move(_M_result));
+ __throw_exception_again;
+ }
+ }
+
typedef __future_base::_Ptr<_Result<_Res>> _Ptr_type;
_Ptr_type _M_result;
_BoundFn _M_fn;
};
- template<typename _BoundFn>
- inline std::shared_ptr<__future_base::_State_base>
- __future_base::_S_make_deferred_state(_BoundFn&& __fn)
- {
- typedef typename remove_reference<_BoundFn>::type __fn_type;
- typedef _Deferred_state<__fn_type> __state_type;
- return std::make_shared<__state_type>(std::move(__fn));
- }
-
- template<typename _BoundFn>
- inline std::shared_ptr<__future_base::_State_base>
- __future_base::_S_make_async_state(_BoundFn&& __fn)
- {
- typedef typename remove_reference<_BoundFn>::type __fn_type;
- typedef _Async_state_impl<__fn_type> __state_type;
- return std::make_shared<__state_type>(std::move(__fn));
- }
-
/// async
template<typename _Fn, typename... _Args>
_GLIBCXX_NODISCARD future<__async_result_of<_Fn, _Args...>>
async(launch __policy, _Fn&& __fn, _Args&&... __args)
{
+ using _Wr = std::thread::_Call_wrapper<_Fn, _Args...>;
+ using _As = __future_base::_Async_state_impl<_Wr>;
+ using _Ds = __future_base::_Deferred_state<_Wr>;
+
std::shared_ptr<__future_base::_State_base> __state;
if ((__policy & launch::async) == launch::async)
{
__try
{
- __state = __future_base::_S_make_async_state(
- std::thread::__make_invoker(std::forward<_Fn>(__fn),
- std::forward<_Args>(__args)...)
- );
+ __state = std::make_shared<_As>(std::forward<_Fn>(__fn),
+ std::forward<_Args>(__args)...);
}
#if __cpp_exceptions
catch(const system_error& __e)
}
if (!__state)
{
- __state = __future_base::_S_make_deferred_state(
- std::thread::__make_invoker(std::forward<_Fn>(__fn),
- std::forward<_Args>(__args)...));
+ __state = std::make_shared<_Ds>(std::forward<_Fn>(__fn),
+ std::forward<_Args>(__args)...);
}
- return future<__async_result_of<_Fn, _Args...>>(__state);
+ return future<__async_result_of<_Fn, _Args...>>(std::move(__state));
}
/// async, potential overload
#else
auto __depend = nullptr;
#endif
- // A call wrapper holding tuple{DECAY_COPY(__f), DECAY_COPY(__args)...}
- using _Invoker_type = _Invoker<__decayed_tuple<_Callable, _Args...>>;
-
- _M_start_thread(_S_make_state<_Invoker_type>(
- std::forward<_Callable>(__f), std::forward<_Args>(__args)...),
+ using _Wrapper = _Call_wrapper<_Callable, _Args...>;
+ // Create a call wrapper with DECAY_COPY(__f) as its target object
+ // and DECAY_COPY(__args)... as its bound argument entities.
+ _M_start_thread(_State_ptr(new _State_impl<_Wrapper>(
+ std::forward<_Callable>(__f), std::forward<_Args>(__args)...)),
__depend);
}
void
_M_start_thread(_State_ptr, void (*)());
- template<typename _Callable, typename... _Args>
- static _State_ptr
- _S_make_state(_Args&&... __args)
- {
- using _Impl = _State_impl<_Callable>;
- return _State_ptr{new _Impl{std::forward<_Args>(__args)...}};
- }
#if _GLIBCXX_THREAD_ABI_COMPAT
public:
struct _Impl_base;
}
};
- template<typename... _Tp>
- using __decayed_tuple = tuple<typename decay<_Tp>::type...>;
-
public:
- // Returns a call wrapper that stores
- // tuple{DECAY_COPY(__callable), DECAY_COPY(__args)...}.
- template<typename _Callable, typename... _Args>
- static _Invoker<__decayed_tuple<_Callable, _Args...>>
- __make_invoker(_Callable&& __callable, _Args&&... __args)
- {
- return { __decayed_tuple<_Callable, _Args...>{
- std::forward<_Callable>(__callable), std::forward<_Args>(__args)...
- } };
- }
+ template<typename... _Tp>
+ using _Call_wrapper = _Invoker<tuple<typename decay<_Tp>::type...>>;
};
inline void
--- /dev/null
+// Copyright (C) 2019-2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do run }
+// { dg-options "-pthread" }
+// { dg-require-effective-target c++11 }
+// { dg-require-effective-target pthread }
+// { dg-require-gthreads "" }
+
+#include <future>
+#include <testsuite_rvalref.h>
+
+struct F : __gnu_test::copycounter
+{
+ F() = default;
+
+ F(const F&) = default;
+
+ // Move constructor copies base class, to use counter:
+ F(F&& f) : copycounter(f) { f.valid = false; }
+
+ void run() { VERIFY(this->valid); }
+};
+
+void
+test01()
+{
+ std::future<void> fut;
+
+ F::copycount = 0;
+ fut = std::async(&F::run, F{});
+ VERIFY( F::copycount == 1 );
+ fut.get();
+ VERIFY( F::copycount == 1 );
+
+ F::copycount = 0;
+ fut = std::async(std::launch::async, &F::run, F{});
+ VERIFY( F::copycount == 1 );
+ fut.get();
+ VERIFY( F::copycount == 1 );
+
+ F::copycount = 0;
+ fut = std::async(std::launch::deferred, &F::run, F{});
+ VERIFY( F::copycount == 1 );
+ fut.get();
+ VERIFY( F::copycount == 1 );
+}
+
+void
+test02()
+{
+ std::future<void> fut;
+ const F f;
+
+ F::copycount = 0;
+ fut = std::async(&F::run, f);
+ VERIFY( F::copycount == 1 );
+ fut.get();
+ VERIFY( F::copycount == 1 );
+
+ F::copycount = 0;
+ fut = std::async(std::launch::async, &F::run, f);
+ VERIFY( F::copycount == 1 );
+ fut.get();
+ VERIFY( F::copycount == 1 );
+
+ F::copycount = 0;
+ fut = std::async(std::launch::deferred, &F::run, f);
+ VERIFY( F::copycount == 1 );
+ fut.get();
+ VERIFY( F::copycount == 1 );
+}
+
+void
+test03()
+{
+ std::future<void> fut;
+ F f;
+
+ F::copycount = 0;
+ fut = std::async(&F::run, std::ref(f));
+ VERIFY( F::copycount == 0 );
+ fut.get();
+ VERIFY( F::copycount == 0 );
+
+ F::copycount = 0;
+ fut = std::async(std::launch::async, &F::run, std::ref(f));
+ VERIFY( F::copycount == 0 );
+ fut.get();
+ VERIFY( F::copycount == 0 );
+
+ F::copycount = 0;
+ fut = std::async(std::launch::deferred, &F::run, std::ref(f));
+ VERIFY( F::copycount == 0 );
+ fut.get();
+ VERIFY( F::copycount == 0 );
+}
+
+int
+main()
+{
+ test01();
+ test02();
+ test03();
+}