diff options
Diffstat (limited to '3rdparty/asio/src/examples/cpp14/executors')
9 files changed, 224 insertions, 239 deletions
diff --git a/3rdparty/asio/src/examples/cpp14/executors/.gitignore b/3rdparty/asio/src/examples/cpp14/executors/.gitignore deleted file mode 100644 index d51d7f00295..00000000000 --- a/3rdparty/asio/src/examples/cpp14/executors/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -actor -async_[0-9] -bank_account_[0-9] -fork_join -pipeline -priority_scheduler diff --git a/3rdparty/asio/src/examples/cpp14/executors/actor.cpp b/3rdparty/asio/src/examples/cpp14/executors/actor.cpp index 26d2fb4bf11..a46caf45a68 100644 --- a/3rdparty/asio/src/examples/cpp14/executors/actor.cpp +++ b/3rdparty/asio/src/examples/cpp14/executors/actor.cpp @@ -1,4 +1,8 @@ -#include <asio/ts/executor.hpp> +#include <asio/any_io_executor.hpp> +#include <asio/defer.hpp> +#include <asio/post.hpp> +#include <asio/strand.hpp> +#include <asio/system_executor.hpp> #include <condition_variable> #include <deque> #include <memory> @@ -6,8 +10,8 @@ #include <typeinfo> #include <vector> +using asio::any_io_executor; using asio::defer; -using asio::executor; using asio::post; using asio::strand; using asio::system_executor; @@ -94,7 +98,7 @@ public: { // Execute the message handler in the context of the target's executor. post(to->executor_, - [=, msg=std::move(msg)] + [=, msg=std::move(msg)]() mutable { to->call_handler(std::move(msg), from); }); @@ -102,7 +106,7 @@ public: protected: // Construct the actor to use the specified executor for all message handlers. - actor(executor e) + actor(any_io_executor e) : executor_(std::move(e)) { } @@ -120,7 +124,7 @@ protected: template <class Actor, class Message> void deregister_handler(void (Actor::* mf)(Message, actor_address)) { - const std::type_info& id = typeid(message_handler<Message>); + const std::type_info& id = typeid(Message); for (auto iter = handlers_.begin(); iter != handlers_.end(); ++iter) { if ((*iter)->message_id() == id) @@ -166,7 +170,7 @@ private: // All messages associated with a single actor object should be processed // non-concurrently. We use a strand to ensure non-concurrent execution even // if the underlying executor may use multiple threads. - strand<executor> executor_; + strand<any_io_executor> executor_; std::vector<std::shared_ptr<message_handler_base>> handlers_; }; @@ -216,7 +220,7 @@ using asio::thread_pool; class member : public actor { public: - explicit member(executor e) + explicit member(any_io_executor e) : actor(std::move(e)) { register_handler(&member::init_handler); diff --git a/3rdparty/asio/src/examples/cpp14/executors/async_1.cpp b/3rdparty/asio/src/examples/cpp14/executors/async_1.cpp index d282b74f206..0d1bdfcb8bd 100644 --- a/3rdparty/asio/src/examples/cpp14/executors/async_1.cpp +++ b/3rdparty/asio/src/examples/cpp14/executors/async_1.cpp @@ -1,29 +1,33 @@ -#include <asio/ts/executor.hpp> -#include <asio/thread_pool.hpp> +#include <asio/associated_executor.hpp> +#include <asio/bind_executor.hpp> +#include <asio/execution.hpp> +#include <asio/static_thread_pool.hpp> #include <iostream> #include <string> using asio::bind_executor; -using asio::dispatch; -using asio::make_work_guard; -using asio::post; -using asio::thread_pool; +using asio::get_associated_executor; +using asio::static_thread_pool; +namespace execution = asio::execution; // A function to asynchronously read a single line from an input stream. -template <class Handler> -void async_getline(std::istream& is, Handler handler) +template <class IoExecutor, class Handler> +void async_getline(IoExecutor io_ex, std::istream& is, Handler handler) { - // Create executor_work for the handler's associated executor. - auto work = make_work_guard(handler); + // Track work for the handler's associated executor. + auto work_ex = asio::prefer( + get_associated_executor(handler, io_ex), + execution::outstanding_work.tracked); // Post a function object to do the work asynchronously. - post([&is, work, handler=std::move(handler)]() mutable + asio::require(io_ex, execution::blocking.never).execute( + [&is, work_ex, handler=std::move(handler)]() mutable { std::string line; std::getline(is, line); // Pass the result to the handler, via the associated executor. - dispatch(work.get_executor(), + asio::prefer(work_ex, execution::blocking.possibly).execute( [line=std::move(line), handler=std::move(handler)]() mutable { handler(std::move(line)); @@ -33,15 +37,18 @@ void async_getline(std::istream& is, Handler handler) int main() { - thread_pool pool; + static_thread_pool io_pool(1); + static_thread_pool completion_pool(1); std::cout << "Enter a line: "; - async_getline(std::cin, - bind_executor(pool, [](std::string line) + async_getline(io_pool.executor(), std::cin, + bind_executor(completion_pool.executor(), + [](std::string line) { std::cout << "Line: " << line << "\n"; })); - pool.join(); + io_pool.wait(); + completion_pool.wait(); } diff --git a/3rdparty/asio/src/examples/cpp14/executors/async_2.cpp b/3rdparty/asio/src/examples/cpp14/executors/async_2.cpp index b39156dcb23..ee4a72e80c3 100644 --- a/3rdparty/asio/src/examples/cpp14/executors/async_2.cpp +++ b/3rdparty/asio/src/examples/cpp14/executors/async_2.cpp @@ -1,30 +1,33 @@ -#include <asio/ts/executor.hpp> -#include <asio/thread_pool.hpp> +#include <asio/associated_executor.hpp> +#include <asio/bind_executor.hpp> +#include <asio/execution.hpp> +#include <asio/static_thread_pool.hpp> #include <iostream> #include <string> using asio::bind_executor; -using asio::dispatch; using asio::get_associated_executor; -using asio::make_work_guard; -using asio::post; -using asio::thread_pool; +using asio::static_thread_pool; +namespace execution = asio::execution; // A function to asynchronously read a single line from an input stream. -template <class Handler> -void async_getline(std::istream& is, Handler handler) +template <class IoExecutor, class Handler> +void async_getline(IoExecutor io_ex, std::istream& is, Handler handler) { - // Create executor_work for the handler's associated executor. - auto work = make_work_guard(handler); + // Track work for the handler's associated executor. + auto work_ex = asio::prefer( + get_associated_executor(handler, io_ex), + execution::outstanding_work.tracked); // Post a function object to do the work asynchronously. - post([&is, work, handler=std::move(handler)]() mutable + asio::require(io_ex, execution::blocking.never).execute( + [&is, work_ex, handler=std::move(handler)]() mutable { std::string line; std::getline(is, line); // Pass the result to the handler, via the associated executor. - dispatch(work.get_executor(), + asio::prefer(work_ex, execution::blocking.possibly).execute( [line=std::move(line), handler=std::move(handler)]() mutable { handler(std::move(line)); @@ -33,36 +36,44 @@ void async_getline(std::istream& is, Handler handler) } // A function to asynchronously read multiple lines from an input stream. -template <class Handler> -void async_getlines(std::istream& is, std::string init, Handler handler) +template <class IoExecutor, class Handler> +void async_getlines(IoExecutor io_ex, std::istream& is, std::string init, Handler handler) { - // Get the final handler's associated executor. - auto ex = get_associated_executor(handler); + // Track work for the I/O executor. + auto io_work_ex = asio::prefer(io_ex, + execution::outstanding_work.tracked); + + // Track work for the handler's associated executor. + auto handler_work_ex = asio::prefer( + get_associated_executor(handler, io_ex), + execution::outstanding_work.tracked); // Use the associated executor for each operation in the composition. - async_getline(is, - bind_executor(ex, - [&is, lines=std::move(init), handler=std::move(handler)] + async_getline(io_work_ex, is, + bind_executor(handler_work_ex, + [io_work_ex, &is, lines=std::move(init), handler=std::move(handler)] (std::string line) mutable { if (line.empty()) handler(lines); else - async_getlines(is, lines + line + "\n", std::move(handler)); + async_getlines(io_work_ex, is, lines + line + "\n", std::move(handler)); })); } int main() { - thread_pool pool; + static_thread_pool io_pool(1); + static_thread_pool completion_pool(1); std::cout << "Enter text, terminating with a blank line:\n"; - async_getlines(std::cin, "", - bind_executor(pool, [](std::string lines) + async_getlines(io_pool.executor(), std::cin, "", + bind_executor(completion_pool.executor(), [](std::string lines) { std::cout << "Lines:\n" << lines << "\n"; })); - pool.join(); + io_pool.wait(); + completion_pool.wait(); } diff --git a/3rdparty/asio/src/examples/cpp14/executors/bank_account_1.cpp b/3rdparty/asio/src/examples/cpp14/executors/bank_account_1.cpp index f85a1852b56..a63d7fc059b 100644 --- a/3rdparty/asio/src/examples/cpp14/executors/bank_account_1.cpp +++ b/3rdparty/asio/src/examples/cpp14/executors/bank_account_1.cpp @@ -1,9 +1,9 @@ -#include <asio/ts/executor.hpp> -#include <asio/thread_pool.hpp> +#include <asio/execution.hpp> +#include <asio/static_thread_pool.hpp> #include <iostream> -using asio::post; -using asio::thread_pool; +using asio::static_thread_pool; +namespace execution = asio::execution; // Traditional active object pattern. // Member functions do not block. @@ -11,37 +11,40 @@ using asio::thread_pool; class bank_account { int balance_ = 0; - mutable thread_pool pool_{1}; + mutable static_thread_pool pool_{1}; public: void deposit(int amount) { - post(pool_, [=] - { - balance_ += amount; - }); + pool_.executor().execute( + [this, amount] + { + balance_ += amount; + }); } void withdraw(int amount) { - post(pool_, [=] - { - if (balance_ >= amount) - balance_ -= amount; - }); + pool_.executor().execute( + [this, amount] + { + if (balance_ >= amount) + balance_ -= amount; + }); } void print_balance() const { - post(pool_, [=] - { - std::cout << "balance = " << balance_ << "\n"; - }); + pool_.executor().execute( + [this] + { + std::cout << "balance = " << balance_ << "\n"; + }); } ~bank_account() { - pool_.join(); + pool_.wait(); } }; diff --git a/3rdparty/asio/src/examples/cpp14/executors/bank_account_2.cpp b/3rdparty/asio/src/examples/cpp14/executors/bank_account_2.cpp index 5233e77dec3..c2de05156e8 100644 --- a/3rdparty/asio/src/examples/cpp14/executors/bank_account_2.cpp +++ b/3rdparty/asio/src/examples/cpp14/executors/bank_account_2.cpp @@ -1,10 +1,9 @@ -#include <asio/ts/executor.hpp> -#include <asio/thread_pool.hpp> +#include <asio/execution.hpp> +#include <asio/static_thread_pool.hpp> #include <iostream> -using asio::post; -using asio::thread_pool; -using asio::use_future; +using asio::static_thread_pool; +namespace execution = asio::execution; // Traditional active object pattern. // Member functions block until operation is finished. @@ -12,35 +11,38 @@ using asio::use_future; class bank_account { int balance_ = 0; - mutable thread_pool pool_{1}; + mutable static_thread_pool pool_{1}; public: void deposit(int amount) { - post(pool_, - use_future([=] + asio::require(pool_.executor(), execution::blocking.always).execute( + [this, amount] { balance_ += amount; - })).get(); + }); } void withdraw(int amount) { - post(pool_, - use_future([=] + asio::require(pool_.executor(), + execution::blocking.always).execute( + [this, amount] { if (balance_ >= amount) balance_ -= amount; - })).get(); + }); } int balance() const { - return post(pool_, - use_future([=] + int result = 0; + asio::require(pool_.executor(), execution::blocking.always).execute( + [this, &result] { - return balance_; - })).get(); + result = balance_; + }); + return result; } }; diff --git a/3rdparty/asio/src/examples/cpp14/executors/fork_join.cpp b/3rdparty/asio/src/examples/cpp14/executors/fork_join.cpp index fe6746ad7e0..7e8a827356d 100644 --- a/3rdparty/asio/src/examples/cpp14/executors/fork_join.cpp +++ b/3rdparty/asio/src/examples/cpp14/executors/fork_join.cpp @@ -1,19 +1,20 @@ -#include <asio/ts/executor.hpp> -#include <asio/thread_pool.hpp> +#include <asio/execution.hpp> +#include <asio/static_thread_pool.hpp> +#include <algorithm> #include <condition_variable> #include <memory> #include <mutex> #include <queue> #include <thread> +#include <numeric> -using asio::dispatch; -using asio::execution_context; -using asio::thread_pool; +using asio::static_thread_pool; +namespace execution = asio::execution; // A fixed-size thread pool used to implement fork/join semantics. Functions // are scheduled using a simple FIFO queue. Implementing work stealing, or // using a queue based on atomic operations, are left as tasks for the reader. -class fork_join_pool : public execution_context +class fork_join_pool { public: // The constructor starts a thread pool with the specified number of threads. @@ -21,7 +22,7 @@ public: // Additional threads may temporarily be added to the pool if they join a // fork_executor. explicit fork_join_pool( - std::size_t thread_count = std::thread::hardware_concurrency() * 2) + std::size_t thread_count = std::max(std::thread::hardware_concurrency(), 1u) * 2) : use_count_(1), threads_(thread_count) { @@ -31,7 +32,8 @@ public: // it is time to shut down, i.e. the use count is zero. for (thread_count_ = 0; thread_count_ < thread_count; ++thread_count_) { - dispatch(threads_, [&] + threads_.executor().execute( + [this] { std::unique_lock<std::mutex> lock(mutex_); while (use_count_ > 0) @@ -43,7 +45,7 @@ public: catch (...) { stop_threads(); - threads_.join(); + threads_.wait(); throw; } } @@ -52,7 +54,7 @@ public: ~fork_join_pool() { stop_threads(); - threads_.join(); + threads_.wait(); } private: @@ -116,7 +118,7 @@ private: // Dispatch a function, executing it immediately if the queue is already // loaded. Otherwise adds the function to the queue and wakes a thread. - void do_dispatch(std::shared_ptr<function_base> p, + void do_execute(std::shared_ptr<function_base> p, const std::shared_ptr<std::size_t>& work_count) { std::unique_lock<std::mutex> lock(mutex_); @@ -134,16 +136,6 @@ private: } } - // Add a function to the queue and wake a thread. - void do_post(std::shared_ptr<function_base> p, - const std::shared_ptr<std::size_t>& work_count) - { - std::lock_guard<std::mutex> lock(mutex_); - queue_.push(p); - do_work_started(work_count); - condition_.notify_one(); - } - // Ask all threads to shut down. void stop_threads() { @@ -157,7 +149,7 @@ private: std::queue<std::shared_ptr<function_base>> queue_; std::size_t use_count_; std::size_t thread_count_; - thread_pool threads_; + static_thread_pool threads_; }; // A class that satisfies the Executor requirements. Every function or piece of @@ -171,45 +163,16 @@ public: { } - fork_join_pool& context() const noexcept + fork_join_pool& query(execution::context_t) const noexcept { return context_; } - void on_work_started() const noexcept - { - std::lock_guard<std::mutex> lock(context_.mutex_); - context_.do_work_started(work_count_); - } - - void on_work_finished() const noexcept - { - std::lock_guard<std::mutex> lock(context_.mutex_); - context_.do_work_finished(work_count_); - } - - template <class Func, class Alloc> - void dispatch(Func&& f, const Alloc& a) const - { - auto p(std::allocate_shared<function<Func>>( - typename std::allocator_traits<Alloc>::template rebind_alloc<char>(a), - std::move(f), work_count_)); - context_.do_dispatch(p, work_count_); - } - - template <class Func, class Alloc> - void post(Func f, const Alloc& a) const - { - auto p(std::allocate_shared<function<Func>>( - typename std::allocator_traits<Alloc>::template rebind_alloc<char>(a), - std::move(f), work_count_)); - context_.do_post(p, work_count_); - } - - template <class Func, class Alloc> - void defer(Func&& f, const Alloc& a) const + template <class Func> + void execute(Func f) const { - post(std::forward<Func>(f), a); + auto p(std::make_shared<function<Func>>(std::move(f), work_count_)); + context_.do_execute(p, work_count_); } friend bool operator==(const fork_executor& a, @@ -288,8 +251,8 @@ void fork_join_sort(Iterator begin, Iterator end) { fork_executor fork(pool); join_guard join(fork); - dispatch(fork, [=]{ fork_join_sort(begin, begin + n / 2); }); - dispatch(fork, [=]{ fork_join_sort(begin + n / 2, end); }); + fork.execute([=]{ fork_join_sort(begin, begin + n / 2); }); + fork.execute([=]{ fork_join_sort(begin + n / 2, end); }); } std::inplace_merge(begin, begin + n / 2, end); } diff --git a/3rdparty/asio/src/examples/cpp14/executors/pipeline.cpp b/3rdparty/asio/src/examples/cpp14/executors/pipeline.cpp index c66e283fcbc..9754a27d425 100644 --- a/3rdparty/asio/src/examples/cpp14/executors/pipeline.cpp +++ b/3rdparty/asio/src/examples/cpp14/executors/pipeline.cpp @@ -1,4 +1,6 @@ -#include <asio/ts/executor.hpp> +#include <asio/associated_executor.hpp> +#include <asio/bind_executor.hpp> +#include <asio/execution.hpp> #include <condition_variable> #include <future> #include <memory> @@ -6,30 +8,21 @@ #include <queue> #include <thread> #include <vector> +#include <cctype> -using asio::execution_context; using asio::executor_binder; using asio::get_associated_executor; -using asio::post; -using asio::system_executor; -using asio::use_future; -using asio::use_service; +namespace execution = asio::execution; // An executor that launches a new thread for each function submitted to it. -// This class satisfies the Executor requirements. +// This class satisfies the executor requirements. class thread_executor { private: - // Service to track all threads started through a thread_executor. - class thread_bag : public execution_context::service + // Singleton execution context that manages threads launched by the new_thread_executor. + class thread_bag { - public: - typedef thread_bag key_type; - - explicit thread_bag(execution_context& ctx) - : execution_context::service(ctx) - { - } + friend class thread_executor; void add_thread(std::thread&& t) { @@ -37,8 +30,9 @@ private: threads_.push_back(std::move(t)); } - private: - virtual void shutdown() + thread_bag() = default; + + ~thread_bag() { for (auto& t : threads_) t.join(); @@ -49,40 +43,24 @@ private: }; public: - execution_context& context() const noexcept + static thread_bag& query(execution::context_t) { - return system_executor().context(); + static thread_bag threads; + return threads; } - void on_work_started() const noexcept + static constexpr auto query(execution::blocking_t) { - // This executor doesn't count work. + return execution::blocking.never; } - void on_work_finished() const noexcept + template <class Func> + void execute(Func f) const { - // This executor doesn't count work. - } - - template <class Func, class Alloc> - void dispatch(Func&& f, const Alloc& a) const - { - post(std::forward<Func>(f), a); - } - - template <class Func, class Alloc> - void post(Func f, const Alloc&) const - { - thread_bag& bag = use_service<thread_bag>(context()); + thread_bag& bag = query(execution::context); bag.add_thread(std::thread(std::move(f))); } - template <class Func, class Alloc> - void defer(Func&& f, const Alloc& a) const - { - post(std::forward<Func>(f), a); - } - friend bool operator==(const thread_executor&, const thread_executor&) noexcept { @@ -185,7 +163,14 @@ std::future<void> pipeline(queue_back<T> in, F f) // Run the function, and as we're the last stage return a future so that the // caller can wait for the pipeline to finish. - return post(ex, use_future([in, f = std::move(f)]() mutable { f(in); })); + std::packaged_task<void()> task( + [in, f = std::move(f)]() mutable + { + f(in); + }); + std::future<void> fut = task.get_future(); + asio::require(ex, execution::blocking.never).execute(std::move(task)); + return fut; } // Launch an intermediate stage in a pipeline. @@ -204,7 +189,8 @@ std::future<void> pipeline(queue_back<T> in, F f, Tail... t) auto ex = get_associated_executor(f, thread_executor()); // Run the function. - post(ex, [in, out, f = std::move(f)]() mutable + asio::require(ex, execution::blocking.never).execute( + [in, out, f = std::move(f)]() mutable { f(in, out); out.stop(); @@ -230,7 +216,8 @@ std::future<void> pipeline(F f, Tail... t) auto ex = get_associated_executor(f, thread_executor()); // Run the function. - post(ex, [out, f = std::move(f)]() mutable + asio::require(ex, execution::blocking.never).execute( + [out, f = std::move(f)]() mutable { f(out); out.stop(); @@ -242,12 +229,12 @@ std::future<void> pipeline(F f, Tail... t) //------------------------------------------------------------------------------ -#include <asio/thread_pool.hpp> +#include <asio/static_thread_pool.hpp> #include <iostream> #include <string> using asio::bind_executor; -using asio::thread_pool; +using asio::static_thread_pool; void reader(queue_front<std::string> out) { @@ -286,8 +273,8 @@ void writer(queue_back<std::string> in) int main() { - thread_pool pool; + static_thread_pool pool(1); - auto f = pipeline(reader, filter, bind_executor(pool, upper), writer); + auto f = pipeline(reader, filter, bind_executor(pool.executor(), upper), writer); f.wait(); } diff --git a/3rdparty/asio/src/examples/cpp14/executors/priority_scheduler.cpp b/3rdparty/asio/src/examples/cpp14/executors/priority_scheduler.cpp index 3b28af1eec0..20d36db933a 100644 --- a/3rdparty/asio/src/examples/cpp14/executors/priority_scheduler.cpp +++ b/3rdparty/asio/src/examples/cpp14/executors/priority_scheduler.cpp @@ -1,66 +1,74 @@ -#include <asio/ts/executor.hpp> +#include <asio/execution.hpp> #include <condition_variable> #include <iostream> #include <memory> #include <mutex> #include <queue> -using asio::dispatch; -using asio::execution_context; +namespace execution = asio::execution; -class priority_scheduler : public execution_context +namespace custom_props { + + struct priority + { + template <typename T> + static constexpr bool is_applicable_property_v = + execution::is_executor<T>::value; + + static constexpr bool is_requirable = true; + static constexpr bool is_preferable = true; + + using polymorphic_query_result_type = int; + + int value() const { return value_; } + + int value_ = 1; + }; + + constexpr priority low_priority{0}; + constexpr priority normal_priority{1}; + constexpr priority high_priority{2}; + +} // namespace custom_props + +class priority_scheduler { public: // A class that satisfies the Executor requirements. class executor_type { public: - executor_type(priority_scheduler& ctx, int pri) noexcept - : context_(ctx), priority_(pri) + executor_type(priority_scheduler& ctx) noexcept + : context_(ctx), priority_(custom_props::normal_priority.value()) { } - priority_scheduler& context() const noexcept + priority_scheduler& query(execution::context_t) const noexcept { return context_; } - void on_work_started() const noexcept - { - // This executor doesn't count work. Instead, the scheduler simply runs - // until explicitly stopped. - } - - void on_work_finished() const noexcept + int query(custom_props::priority) const noexcept { - // This executor doesn't count work. Instead, the scheduler simply runs - // until explicitly stopped. + return priority_; } - template <class Func, class Alloc> - void dispatch(Func&& f, const Alloc& a) const + executor_type require(custom_props::priority pri) const { - post(std::forward<Func>(f), a); + executor_type new_ex(*this); + new_ex.priority_ = pri.value(); + return new_ex; } - template <class Func, class Alloc> - void post(Func f, const Alloc& a) const + template <class Func> + void execute(Func f) const { - auto p(std::allocate_shared<item<Func>>( - typename std::allocator_traits< - Alloc>::template rebind_alloc<char>(a), - priority_, std::move(f))); + auto p(std::make_shared<item<Func>>(priority_, std::move(f))); std::lock_guard<std::mutex> lock(context_.mutex_); context_.queue_.push(p); context_.condition_.notify_one(); } - template <class Func, class Alloc> - void defer(Func&& f, const Alloc& a) const - { - post(std::forward<Func>(f), a); - } - friend bool operator==(const executor_type& a, const executor_type& b) noexcept { @@ -78,9 +86,9 @@ public: int priority_; }; - executor_type get_executor(int pri = 0) noexcept + executor_type executor() noexcept { - return executor_type(*const_cast<priority_scheduler*>(this), pri); + return executor_type(*const_cast<priority_scheduler*>(this)); } void run() @@ -152,16 +160,22 @@ private: int main() { priority_scheduler sched; - auto low = sched.get_executor(0); - auto med = sched.get_executor(1); - auto high = sched.get_executor(2); - dispatch(low, []{ std::cout << "1\n"; }); - dispatch(low, []{ std::cout << "11\n"; }); - dispatch(med, []{ std::cout << "2\n"; }); - dispatch(med, []{ std::cout << "22\n"; }); - dispatch(high, []{ std::cout << "3\n"; }); - dispatch(high, []{ std::cout << "33\n"; }); - dispatch(high, []{ std::cout << "333\n"; }); - dispatch(sched.get_executor(-1), [&]{ sched.stop(); }); + auto ex = sched.executor(); + auto prefer_low = asio::prefer(ex, custom_props::low_priority); + auto low = asio::require(ex, custom_props::low_priority); + auto med = asio::require(ex, custom_props::normal_priority); + auto high = asio::require(ex, custom_props::high_priority); + execution::any_executor<custom_props::priority> poly_high(high); + prefer_low.execute([]{ std::cout << "1\n"; }); + low.execute([]{ std::cout << "11\n"; }); + low.execute([]{ std::cout << "111\n"; }); + med.execute([]{ std::cout << "2\n"; }); + med.execute([]{ std::cout << "22\n"; }); + high.execute([]{ std::cout << "3\n"; }); + high.execute([]{ std::cout << "33\n"; }); + high.execute([]{ std::cout << "333\n"; }); + poly_high.execute([]{ std::cout << "3333\n"; }); + asio::require(ex, custom_props::priority{-1}).execute([&]{ sched.stop(); }); sched.run(); + std::cout << "polymorphic query result = " << asio::query(poly_high, custom_props::priority{}) << "\n"; } |