summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/asio/src/examples/cpp14/executors
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/asio/src/examples/cpp14/executors')
-rw-r--r--3rdparty/asio/src/examples/cpp14/executors/.gitignore6
-rw-r--r--3rdparty/asio/src/examples/cpp14/executors/actor.cpp18
-rw-r--r--3rdparty/asio/src/examples/cpp14/executors/async_1.cpp39
-rw-r--r--3rdparty/asio/src/examples/cpp14/executors/async_2.cpp59
-rw-r--r--3rdparty/asio/src/examples/cpp14/executors/bank_account_1.cpp41
-rw-r--r--3rdparty/asio/src/examples/cpp14/executors/bank_account_2.cpp34
-rw-r--r--3rdparty/asio/src/examples/cpp14/executors/fork_join.cpp79
-rw-r--r--3rdparty/asio/src/examples/cpp14/executors/pipeline.cpp85
-rw-r--r--3rdparty/asio/src/examples/cpp14/executors/priority_scheduler.cpp102
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";
}