]> git.sesse.net Git - casparcg/commitdiff
2.1.0: -async: Refactored. Call thread.join() when futures created with launch::async...
authorronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Mon, 20 Feb 2012 13:47:34 +0000 (13:47 +0000)
committerronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Mon, 20 Feb 2012 13:47:34 +0000 (13:47 +0000)
git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches/2.1.0@2471 362d55ac-95cf-4e76-9f9a-cbaa9c17b72d

common/future.h

index b093fe50a99a0c9c02045926901ea1b4a0a39123..c4b88b75df81c52f92bc74fb860457c842a06506 100644 (file)
@@ -21,18 +21,54 @@ struct launch_policy_def
 typedef caspar::enum_class<launch_policy_def> launch;\r
 \r
 namespace detail {\r
+       \r
+template<typename R>\r
+struct future_object_helper\r
+{      \r
+       template<typename T, typename F>\r
+       static void invoke(T& future_object, F& f)\r
+       {                               \r
+        try\r
+        {\r
+                       future_object.mark_finished_with_result_internal(f());\r
+        }\r
+        catch(...)\r
+        {\r
+                       future_object.mark_exceptional_finish_internal(boost::current_exception());\r
+        }\r
+       }\r
+};\r
+\r
+template<>\r
+struct future_object_helper<void>\r
+{      \r
+       template<typename T, typename F>\r
+       static void invoke(T& future_object, F& f)\r
+       {                               \r
+        try\r
+        {\r
+                       f();\r
+                       future_object.mark_finished_with_result_internal();\r
+        }\r
+        catch(...)\r
+        {\r
+                       future_object.mark_exceptional_finish_internal(boost::current_exception());\r
+        }\r
+       }\r
+};\r
 \r
 template<typename R, typename F>\r
-struct callback_object: public boost::detail::future_object<R>\r
+struct deferred_future_object : public boost::detail::future_object<R>\r
 {      \r
        F f;\r
        bool done;\r
 \r
        template<typename F2>\r
-       callback_object(F2&& f)\r
+       deferred_future_object(F2&& f)\r
                : f(std::forward<F2>(f))\r
                , done(false)\r
        {\r
+               set_wait_callback(std::mem_fn(&detail::deferred_future_object<R, F>::operator()), this);\r
        }\r
                \r
        void operator()()\r
@@ -42,50 +78,35 @@ struct callback_object: public boost::detail::future_object<R>
                if(done)\r
                        return;\r
 \r
-        try\r
-        {\r
-                       this->mark_finished_with_result_internal(f());\r
-        }\r
-        catch(...)\r
-        {\r
-                       this->mark_exceptional_finish_internal(boost::current_exception());\r
-        }\r
+               future_object_helper<R>::invoke(*this, f);\r
 \r
                done = true;\r
        }\r
 };\r
 \r
-template<typename F>\r
-struct callback_object<void, F> : public boost::detail::future_object<void>\r
+template<typename R, typename F>\r
+struct async_future_object : public boost::detail::future_object<R>\r
 {      \r
        F f;\r
-       bool done;\r
+       boost::thread thread;\r
 \r
        template<typename F2>\r
-       callback_object(F2&& f)\r
+       async_future_object(F2&& f)\r
                : f(std::forward<F2>(f))\r
-               , done(false)\r
+               , thread([this]{run();})\r
        {\r
        }\r
 \r
-       void operator()()\r
+       ~async_future_object()\r
        {\r
-               boost::lock_guard<boost::mutex> lock2(mutex);\r
-               \r
-               if(done)\r
-                       return;\r
+               thread.join();\r
+       }\r
 \r
-        try\r
-        {\r
-                       f();\r
-                       this->mark_finished_with_result_internal();\r
-               }\r
-        catch(...)\r
-        {\r
-                       this->mark_exceptional_finish_internal(boost::current_exception());\r
-        }\r
+       void run()\r
+       {\r
+               boost::lock_guard<boost::mutex> lock2(mutex);           \r
 \r
-               done = true;\r
+               future_object_helper<R>::invoke(*this, f);\r
        }\r
 };\r
 \r
@@ -94,40 +115,24 @@ struct callback_object<void, F> : public boost::detail::future_object<void>
 template<typename F>\r
 auto async(launch policy, F&& f) -> boost::unique_future<decltype(f())>\r
 {              \r
-       typedef decltype(f()) result_type;\r
-       \r
-       if((policy & launch::async) != 0)\r
-       {\r
-               typedef boost::packaged_task<result_type> task_t;\r
+       typedef decltype(f())                                                           result_type;    \r
+       typedef boost::detail::future_object<result_type>       future_object_type;\r
 \r
-               auto task       = task_t(std::forward<F>(f));   \r
-               auto future = task.get_future();\r
-               \r
-               boost::thread(std::move(task)).detach();\r
-       \r
-               return std::move(future);\r
-       }\r
-       else if((policy & launch::deferred) != 0)\r
-       {               \r
-               // HACK: THIS IS A MAYOR HACK!\r
-\r
-               typedef boost::detail::future_object<result_type> future_object_t;\r
-                                       \r
-               auto callback_object     = boost::make_shared<detail::callback_object<result_type, F>>(std::forward<F>(f));\r
-               auto callback_object_raw = callback_object.get();\r
-               auto future_object               = boost::static_pointer_cast<future_object_t>(std::move(callback_object));\r
-\r
-               future_object->set_wait_callback(std::mem_fn(&detail::callback_object<result_type, F>::operator()), callback_object_raw);\r
-               \r
-               boost::unique_future<result_type> future;\r
+       boost::shared_ptr<future_object_type> future_object;\r
 \r
-               static_assert(sizeof(future) == sizeof(future_object), "");\r
-\r
-               reinterpret_cast<boost::shared_ptr<future_object_t>&>(future) = std::move(future_object); // Get around the "private" encapsulation.\r
-               return std::move(future);\r
-       }\r
+       if((policy & launch::async) != 0)\r
+               future_object = boost::static_pointer_cast<future_object_type>(boost::make_shared<detail::async_future_object<result_type, F>>(std::forward<F>(f)));\r
+       else if((policy & launch::deferred) != 0)\r
+               future_object = boost::static_pointer_cast<future_object_type>(boost::make_shared<detail::deferred_future_object<result_type, F>>(std::forward<F>(f))); \r
        else\r
                throw std::invalid_argument("policy");\r
+       \r
+       boost::unique_future<result_type> future;\r
+\r
+       static_assert(sizeof(future) == sizeof(future_object), "");\r
+\r
+       reinterpret_cast<boost::shared_ptr<future_object_type>&>(future) = std::move(future_object); // Get around the "private" encapsulation.\r
+       return std::move(future);\r
 }\r
        \r
 template<typename F>\r