소스 검색

I had a giant misunderstanding of what 'synchronizes with' meant in [futures.async]/p5. This invalidated the current design of async in <future>. This is a new design, based on my new understanding, which has been confirmed on the lwg mailing list. The summary is that ~future() (and ~shared_future()) will block when they are created from within async, and the thread hasn't finished yet. As part of this work I created two new type traits: __invokable<F, Args...>::value and __invoke_of<F, Args...>::type. These are what result_of<F(Args...)> wanted to be when it grew up, but never will be. __invoke_of is carefully crafted so that it can serve as its own enable_if (type doesn't exist if the signature isn't invokable). All of this work is C++11 only.

git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@131639 91177308-0d34-0410-b5e6-96231b3b80d8
Howard Hinnant 14 년 전
부모
커밋
57cff290a4
5개의 변경된 파일316개의 추가작업 그리고 23개의 파일을 삭제
  1. 2 2
      include/__functional_base
  2. 186 18
      include/future
  3. 1 1
      include/mutex
  4. 1 1
      include/thread
  5. 126 1
      include/type_traits

+ 2 - 2
include/__functional_base

@@ -440,7 +440,7 @@ __invoke(_R (*__f)(_Param...), _Args&& ...__args)
 
 
 template <class _F, class ..._T>
 template <class _F, class ..._T>
 inline _LIBCPP_INLINE_VISIBILITY
 inline _LIBCPP_INLINE_VISIBILITY
-typename result_of<_F(_T...)>::type
+typename __invoke_of<_F, _T...>::type
 __invoke(_F&& __f, _T&& ...__t)
 __invoke(_F&& __f, _T&& ...__t)
 {
 {
     return _STD::forward<_F>(__f)(_STD::forward<_T>(__t)...);
     return _STD::forward<_F>(__f)(_STD::forward<_T>(__t)...);
@@ -476,7 +476,7 @@ public:
     // invoke
     // invoke
     template <class... _ArgTypes>
     template <class... _ArgTypes>
        _LIBCPP_INLINE_VISIBILITY
        _LIBCPP_INLINE_VISIBILITY
-       typename __invoke_return<type&, _ArgTypes...>::type
+       typename __invoke_of<type&, _ArgTypes...>::type
           operator() (_ArgTypes&&... __args) const
           operator() (_ArgTypes&&... __args) const
           {
           {
               return __invoke(get(), _STD::forward<_ArgTypes>(__args)...);
               return __invoke(get(), _STD::forward<_ArgTypes>(__args)...);

+ 186 - 18
include/future

@@ -858,6 +858,115 @@ __deferred_assoc_state<void, _F>::__execute()
 #endif  // _LIBCPP_NO_EXCEPTIONS
 #endif  // _LIBCPP_NO_EXCEPTIONS
 }
 }
 
 
+template <class _R, class _F>
+class __async_assoc_state
+    : public __assoc_state<_R>
+{
+    typedef __assoc_state<_R> base;
+
+    _F __func_;
+
+    virtual void __on_zero_shared();
+public:
+#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
+    explicit __async_assoc_state(_F&& __f);
+#endif
+
+    virtual void __execute();
+};
+
+#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
+
+template <class _R, class _F>
+inline _LIBCPP_INLINE_VISIBILITY
+__async_assoc_state<_R, _F>::__async_assoc_state(_F&& __f)
+    : __func_(_STD::forward<_F>(__f))
+{
+}
+
+#endif  // _LIBCPP_HAS_NO_RVALUE_REFERENCES
+
+template <class _R, class _F>
+void
+__async_assoc_state<_R, _F>::__execute()
+{
+#ifndef _LIBCPP_NO_EXCEPTIONS
+    try
+    {
+#endif  // _LIBCPP_NO_EXCEPTIONS
+        this->set_value(__func_());
+#ifndef _LIBCPP_NO_EXCEPTIONS
+    }
+    catch (...)
+    {
+        this->set_exception(current_exception());
+    }
+#endif  // _LIBCPP_NO_EXCEPTIONS
+}
+
+template <class _R, class _F>
+void
+__async_assoc_state<_R, _F>::__on_zero_shared()
+{
+    this->wait();
+    base::__on_zero_shared();
+}
+
+template <class _F>
+class __async_assoc_state<void, _F>
+    : public __assoc_sub_state
+{
+    typedef __assoc_sub_state base;
+
+    _F __func_;
+
+    virtual void __on_zero_shared();
+public:
+#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
+    explicit __async_assoc_state(_F&& __f);
+#endif
+
+    virtual void __execute();
+};
+
+#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
+
+template <class _F>
+inline _LIBCPP_INLINE_VISIBILITY
+__async_assoc_state<void, _F>::__async_assoc_state(_F&& __f)
+    : __func_(_STD::forward<_F>(__f))
+{
+}
+
+#endif  // _LIBCPP_HAS_NO_RVALUE_REFERENCES
+
+template <class _F>
+void
+__async_assoc_state<void, _F>::__execute()
+{
+#ifndef _LIBCPP_NO_EXCEPTIONS
+    try
+    {
+#endif  // _LIBCPP_NO_EXCEPTIONS
+        __func_();
+        this->set_value();
+#ifndef _LIBCPP_NO_EXCEPTIONS
+    }
+    catch (...)
+    {
+        this->set_exception(current_exception());
+    }
+#endif  // _LIBCPP_NO_EXCEPTIONS
+}
+
+template <class _F>
+void
+__async_assoc_state<void, _F>::__on_zero_shared()
+{
+    this->wait();
+    base::__on_zero_shared();
+}
+
 template <class> class promise;
 template <class> class promise;
 template <class> class shared_future;
 template <class> class shared_future;
 template <class> class atomic_future;
 template <class> class atomic_future;
@@ -874,6 +983,14 @@ __make_deferred_assoc_state(_F&& __f);
 __make_deferred_assoc_state(_F __f);
 __make_deferred_assoc_state(_F __f);
 #endif
 #endif
 
 
+template <class _R, class _F>
+future<_R>
+#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
+__make_async_assoc_state(_F&& __f);
+#else
+__make_async_assoc_state(_F __f);
+#endif
+
 template <class _R>
 template <class _R>
 class _LIBCPP_VISIBLE future
 class _LIBCPP_VISIBLE future
 {
 {
@@ -885,11 +1002,16 @@ class _LIBCPP_VISIBLE future
     template <class> friend class shared_future;
     template <class> friend class shared_future;
     template <class> friend class atomic_future;
     template <class> friend class atomic_future;
 
 
-    template <class _R1, class _F>
 #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
 #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
+    template <class _R1, class _F>
         friend future<_R1> __make_deferred_assoc_state(_F&& __f);
         friend future<_R1> __make_deferred_assoc_state(_F&& __f);
+    template <class _R1, class _F>
+        friend future<_R1> __make_async_assoc_state(_F&& __f);
 #else
 #else
+    template <class _R1, class _F>
         friend future<_R1> __make_deferred_assoc_state(_F __f);
         friend future<_R1> __make_deferred_assoc_state(_F __f);
+    template <class _R1, class _F>
+        friend future<_R1> __make_async_assoc_state(_F __f);
 #endif
 #endif
 
 
 public:
 public:
@@ -983,11 +1105,16 @@ class _LIBCPP_VISIBLE future<_R&>
     template <class> friend class shared_future;
     template <class> friend class shared_future;
     template <class> friend class atomic_future;
     template <class> friend class atomic_future;
 
 
-    template <class _R1, class _F>
 #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
 #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
+    template <class _R1, class _F>
         friend future<_R1> __make_deferred_assoc_state(_F&& __f);
         friend future<_R1> __make_deferred_assoc_state(_F&& __f);
+    template <class _R1, class _F>
+        friend future<_R1> __make_async_assoc_state(_F&& __f);
 #else
 #else
+    template <class _R1, class _F>
         friend future<_R1> __make_deferred_assoc_state(_F __f);
         friend future<_R1> __make_deferred_assoc_state(_F __f);
+    template <class _R1, class _F>
+        friend future<_R1> __make_async_assoc_state(_F __f);
 #endif
 #endif
 
 
 public:
 public:
@@ -1076,11 +1203,16 @@ class _LIBCPP_VISIBLE future<void>
     template <class> friend class shared_future;
     template <class> friend class shared_future;
     template <class> friend class atomic_future;
     template <class> friend class atomic_future;
 
 
-    template <class _R1, class _F>
 #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
 #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
+    template <class _R1, class _F>
         friend future<_R1> __make_deferred_assoc_state(_F&& __f);
         friend future<_R1> __make_deferred_assoc_state(_F&& __f);
+    template <class _R1, class _F>
+        friend future<_R1> __make_async_assoc_state(_F&& __f);
 #else
 #else
+    template <class _R1, class _F>
         friend future<_R1> __make_deferred_assoc_state(_F __f);
         friend future<_R1> __make_deferred_assoc_state(_F __f);
+    template <class _R1, class _F>
+        friend future<_R1> __make_async_assoc_state(_F __f);
 #endif
 #endif
 
 
 public:
 public:
@@ -2034,32 +2166,68 @@ __make_deferred_assoc_state(_F __f)
     return future<_R>(__h.get());
     return future<_R>(__h.get());
 }
 }
 
 
+template <class _R, class _F>
+future<_R>
+#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
+__make_async_assoc_state(_F&& __f)
+#else
+__make_async_assoc_state(_F __f)
+#endif
+{
+    unique_ptr<__async_assoc_state<_R, _F>, __release_shared_count>
+        __h(new __async_assoc_state<_R, _F>(_STD::forward<_F>(__f)));
+    _STD::thread(&__async_assoc_state<_R, _F>::__execute, __h.get()).detach();
+    return future<_R>(__h.get());
+}
+
 template <class _F, class... _Args>
 template <class _F, class... _Args>
-future<typename result_of<_F(_Args...)>::type>
+class __async_func
+{
+    tuple<_F, _Args...> __f_;
+
+public:
+    typedef typename __invoke_of<_F, _Args...>::type _R;
+
+    _LIBCPP_INLINE_VISIBILITY
+    explicit __async_func(_F&& __f, _Args&&... __args)
+        : __f_(_STD::move(__f), _STD::move(__args)...) {}
+
+    _LIBCPP_INLINE_VISIBILITY
+    __async_func(__async_func&& __f) : __f_(_STD::move(__f.__f_)) {}
+
+    _R operator()()
+    {
+        typedef typename __make_tuple_indices<1+sizeof...(_Args), 1>::type _Index;
+        return __execute(_Index());
+    }
+private:
+    template <size_t ..._Indices>
+    _R
+    __execute(__tuple_indices<_Indices...>)
+    {
+        return __invoke(_STD::move(_STD::get<0>(__f_)), _STD::move(_STD::get<_Indices>(__f_))...);
+    }
+};
+
+template <class _F, class... _Args>
+future<typename __invoke_of<typename decay<_F>::type, typename decay<_Args>::type...>::type>
 async(launch __policy, _F&& __f, _Args&&... __args)
 async(launch __policy, _F&& __f, _Args&&... __args)
 {
 {
-    typedef typename result_of<_F(_Args...)>::type _R;
+    typedef __async_func<typename decay<_F>::type, typename decay<_Args>::type...> _BF;
+    typedef typename _BF::_R _R;
     future<_R> __r;
     future<_R> __r;
     if (__policy & launch::async)
     if (__policy & launch::async)
-    {
-        packaged_task<_R()> __pk(bind(_STD::forward<_F>(__f),
-                                      _STD::forward<_Args>(__args)...));
-        __r = __pk.get_future();
-        thread(_STD::move(__pk)).detach();
-    }
+        __r = _STD::__make_async_assoc_state<_R>(_BF(__decay_copy(_STD::forward<_F>(__f)),
+                                                     __decay_copy(_STD::forward<_Args>(__args))...));
     else if (__policy & launch::deferred)
     else if (__policy & launch::deferred)
-        __r = _STD::__make_deferred_assoc_state<_R>(bind(_STD::forward<_F>(__f),
-                                              _STD::forward<_Args>(__args)...));
+        __r = _STD::__make_deferred_assoc_state<_R>(_BF(__decay_copy(_STD::forward<_F>(__f)),
+                                                        __decay_copy(_STD::forward<_Args>(__args))...));
     return __r;
     return __r;
 }
 }
 
 
 template <class _F, class... _Args>
 template <class _F, class... _Args>
 inline _LIBCPP_INLINE_VISIBILITY
 inline _LIBCPP_INLINE_VISIBILITY
-typename enable_if
-<
-    !is_same<typename decay<_F>::type, launch>::value,
-    future<typename result_of<_F(_Args...)>::type>
->::type
+future<typename __invoke_of<typename decay<_F>::type, typename decay<_Args>::type...>::type>
 async(_F&& __f, _Args&&... __args)
 async(_F&& __f, _Args&&... __args)
 {
 {
     return _STD::async(launch::any, _STD::forward<_F>(__f),
     return _STD::async(launch::any, _STD::forward<_F>(__f),

+ 1 - 1
include/mutex

@@ -485,7 +485,7 @@ private:
     _LIBCPP_INLINE_VISIBILITY
     _LIBCPP_INLINE_VISIBILITY
     void __execute(__tuple_indices<_Indices...>)
     void __execute(__tuple_indices<_Indices...>)
     {
     {
-        _STD::move(_STD::get<0>(__f_))(_STD::move(_STD::get<_Indices>(__f_))...);
+        __invoke(_STD::move(_STD::get<0>(__f_)), _STD::move(_STD::get<_Indices>(__f_))...);
     }
     }
 };
 };
 
 

+ 1 - 1
include/thread

@@ -325,7 +325,7 @@ inline _LIBCPP_INLINE_VISIBILITY
 void
 void
 __threaad_execute(tuple<_F, _Args...>& __t, __tuple_indices<_Indices...>)
 __threaad_execute(tuple<_F, _Args...>& __t, __tuple_indices<_Indices...>)
 {
 {
-    _STD::move(_STD::get<0>(__t))(_STD::move(_STD::get<_Indices>(__t))...);
+    __invoke(_STD::move(_STD::get<0>(__t)), _STD::move(_STD::get<_Indices>(__t))...);
 }
 }
 
 
 template <class _F>
 template <class _F>

+ 126 - 1
include/type_traits

@@ -2772,7 +2772,132 @@ template <class _Tp> struct _LIBCPP_VISIBLE is_trivial
                                  is_trivially_default_constructible<_Tp>::value>
                                  is_trivially_default_constructible<_Tp>::value>
 #endif
 #endif
     {};
     {};
-    
+
+#ifndef _LIBCPP_HAS_NO_VARIADICS
+
+// __invokable
+
+template <unsigned, class _F, class ..._Args>
+struct __invokable_imp
+    : false_type
+{
+};
+
+// __invokable member function pointer
+
+template <class _A0, class _F, class ..._Args>
+auto
+__invokable_mfp_test(_A0&& __a0, _F __f, _Args&& ...__args)
+    -> decltype((_STD::forward<_A0>(__a0).*__f)(_STD::forward<_Args>(__args)...));
+
+template <class _A0, class _F, class ..._Args>
+auto
+__invokable_mfp_test(_A0&& __a0, _F __f, _Args&& ...__args)
+    -> decltype(((*_STD::forward<_A0>(__a0)).*__f)(_STD::forward<_Args>(__args)...));
+
+template <class _F, class ..._Args>
+auto
+__invokable_mfp_test(__any, _F __f, _Args&& ...__args)
+    -> __nat;
+
+template <class _F, class _A0, class ..._Args>
+struct __invokable_imp<2, _F, _A0, _Args...>
+{
+    typedef decltype(
+            __invokable_mfp_test(_STD::declval<_A0>(), _STD::declval<_F>(),
+                                 _STD::declval<_Args>()...)
+                    ) type;
+    static const bool value = !is_same<type, __nat>::value;
+};
+
+// __invokable member object pointer
+
+template <class _A0, class _F>
+auto
+__invokable_mop_test(_A0&& __a0, _F __f)
+    -> decltype(_STD::forward<_A0>(__a0).*__f);
+
+template <class _A0, class _F>
+auto
+__invokable_mop_test(_A0&& __a0, _F __f)
+    -> decltype((*_STD::forward<_A0>(__a0)).*__f);
+
+template <class _F>
+auto
+__invokable_mop_test(__any, _F __f)
+    -> __nat;
+
+template <class _F, class _A0>
+struct __invokable_imp<1, _F, _A0>
+{
+    typedef decltype(
+                 __invokable_mop_test(_STD::declval<_A0>(), _STD::declval<_F>())
+                    ) type;
+    static const bool value = !is_same<type, __nat>::value;
+};
+
+// __invokable other
+
+template <class _F, class ..._Args>
+auto
+__invokable_other_test(_F&& __f, _Args&& ...__args)
+    -> decltype(_STD::forward<_F>(__f)(_STD::forward<_Args>(__args)...));
+
+template <class ..._Args>
+auto
+__invokable_other_test(__any, _Args&& ...__args)
+    -> __nat;
+
+template <class _F, class ..._Args>
+struct __invokable_imp<0, _F, _Args...>
+{
+    typedef decltype(
+            __invokable_other_test(_STD::declval<_F>(), _STD::declval<_Args>()...)
+                    ) type;
+    static const bool value = !is_same<type, __nat>::value;
+};
+
+// __invokable_classify
+
+template <class _F>
+struct __invokable_classify
+{
+    typedef typename remove_reference<_F>::type _FR;
+    static const unsigned value = is_member_function_pointer<_FR>::value ?
+                                  2 :
+                                  is_member_object_pointer<_FR>::value ?
+                                  1 :
+                                  0;
+};
+
+template <class _F, class ..._Args>
+struct __invokable
+    : public integral_constant<bool,
+          __invokable_imp<__invokable_classify<_F>::value, _F, _Args...>::value>
+{
+};
+
+// __invoke_of
+
+template <bool _Invokable, class _F, class ..._Args>
+struct __invoke_of_imp  // false
+{
+};
+
+template <class _F, class ..._Args>
+struct __invoke_of_imp<true, _F, _Args...>
+{
+    typedef typename __invokable_imp<__invokable_classify<_F>::value, _F, _Args...>::type type;
+};
+
+template <class _F, class ..._Args>
+struct __invoke_of
+    : public __invoke_of_imp<__invokable<_F, _Args...>::value, _F, _Args...>
+{
+};
+
+#endif  // _LIBCPP_HAS_NO_VARIADICS
+
 template <class _Tp>
 template <class _Tp>
 inline _LIBCPP_INLINE_VISIBILITY
 inline _LIBCPP_INLINE_VISIBILITY
 void
 void