[DEV] add v1.76.0

This commit is contained in:
2021-10-05 21:37:46 +02:00
parent a97e9ae7d4
commit d0115b733d
45133 changed files with 4744437 additions and 1026325 deletions

View File

@@ -1,45 +1,31 @@
#
# Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
# Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
#
# Distributed under the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#
import os ;
if [ os.name ] = SOLARIS
{
lib socket ;
lib nsl ;
}
else if [ os.name ] = NT
{
lib ws2_32 ;
lib mswsock ;
}
else if [ os.name ] = HPUX
{
lib ipv6 ;
}
else if [ os.name ] = HAIKU
{
lib network ;
}
lib socket ; # SOLARIS
lib nsl ; # SOLARIS
lib ws2_32 ; # NT
lib mswsock ; # NT
lib ipv6 ; # HPUX
lib network ; # HAIKU
project
: requirements
<library>/boost/system//boost_system
<define>BOOST_ALL_NO_LIB=1
<threading>multi
<os>SOLARIS:<library>socket
<os>SOLARIS:<library>nsl
<os>NT:<define>_WIN32_WINNT=0x0501
<os>NT,<toolset>gcc:<library>ws2_32
<os>NT,<toolset>gcc:<library>mswsock
<os>NT,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS
<os>HPUX,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED
<os>HPUX:<library>ipv6
<os>HAIKU:<library>network
<target-os>solaris:<library>socket
<target-os>solaris:<library>nsl
<target-os>windows:<define>_WIN32_WINNT=0x0501
<target-os>windows,<toolset>gcc:<library>ws2_32
<target-os>windows,<toolset>gcc:<library>mswsock
<target-os>windows,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS
<target-os>hpux,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED
<target-os>hpux:<library>ipv6
<target-os>haiku:<library>network
;
exe actor : actor.cpp ;

View File

@@ -1,5 +1,5 @@
#include <boost/asio/any_io_executor.hpp>
#include <boost/asio/defer.hpp>
#include <boost/asio/executor.hpp>
#include <boost/asio/post.hpp>
#include <boost/asio/strand.hpp>
#include <boost/asio/system_executor.hpp>
@@ -10,8 +10,8 @@
#include <typeinfo>
#include <vector>
using boost::asio::any_io_executor;
using boost::asio::defer;
using boost::asio::executor;
using boost::asio::post;
using boost::asio::strand;
using boost::asio::system_executor;
@@ -106,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))
{
}
@@ -124,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)
@@ -171,7 +171,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_;
};
@@ -221,7 +221,7 @@ using boost::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);

View File

@@ -1,9 +1,9 @@
#include <boost/asio/post.hpp>
#include <boost/asio/thread_pool.hpp>
#include <boost/asio/execution.hpp>
#include <boost/asio/static_thread_pool.hpp>
#include <iostream>
using boost::asio::post;
using boost::asio::thread_pool;
using boost::asio::static_thread_pool;
namespace execution = boost::asio::execution;
// Traditional active object pattern.
// Member functions do not block.
@@ -11,37 +11,43 @@ using boost::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;
});
execution::execute(
pool_.executor(),
[this, amount]
{
balance_ += amount;
});
}
void withdraw(int amount)
{
post(pool_, [=]
{
if (balance_ >= amount)
balance_ -= amount;
});
execution::execute(
pool_.executor(),
[this, amount]
{
if (balance_ >= amount)
balance_ -= amount;
});
}
void print_balance() const
{
post(pool_, [=]
{
std::cout << "balance = " << balance_ << "\n";
});
execution::execute(
pool_.executor(),
[this]
{
std::cout << "balance = " << balance_ << "\n";
});
}
~bank_account()
{
pool_.join();
pool_.wait();
}
};

View File

@@ -1,11 +1,9 @@
#include <boost/asio/post.hpp>
#include <boost/asio/thread_pool.hpp>
#include <boost/asio/use_future.hpp>
#include <boost/asio/execution.hpp>
#include <boost/asio/static_thread_pool.hpp>
#include <iostream>
using boost::asio::post;
using boost::asio::thread_pool;
using boost::asio::use_future;
using boost::asio::static_thread_pool;
namespace execution = boost::asio::execution;
// Traditional active object pattern.
// Member functions block until operation is finished.
@@ -13,35 +11,43 @@ using boost::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([=]
execution::execute(
boost::asio::require(pool_.executor(),
execution::blocking.always),
[this, amount]
{
balance_ += amount;
})).get();
});
}
void withdraw(int amount)
{
post(pool_,
use_future([=]
execution::execute(
boost::asio::require(pool_.executor(),
execution::blocking.always),
[this, amount]
{
if (balance_ >= amount)
balance_ -= amount;
})).get();
});
}
int balance() const
{
return post(pool_,
use_future([=]
int result = 0;
execution::execute(
boost::asio::require(pool_.executor(),
execution::blocking.always),
[this, &result]
{
return balance_;
})).get();
result = balance_;
});
return result;
}
};

View File

@@ -1,20 +1,20 @@
#include <boost/asio/dispatch.hpp>
#include <boost/asio/execution_context.hpp>
#include <boost/asio/thread_pool.hpp>
#include <boost/asio/execution.hpp>
#include <boost/asio/static_thread_pool.hpp>
#include <algorithm>
#include <condition_variable>
#include <memory>
#include <mutex>
#include <queue>
#include <thread>
#include <numeric>
using boost::asio::dispatch;
using boost::asio::execution_context;
using boost::asio::thread_pool;
using boost::asio::static_thread_pool;
namespace execution = boost::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.
@@ -22,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)
{
@@ -32,7 +32,9 @@ 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_, [&]
execution::execute(
threads_.executor(),
[this]
{
std::unique_lock<std::mutex> lock(mutex_);
while (use_count_ > 0)
@@ -44,7 +46,7 @@ public:
catch (...)
{
stop_threads();
threads_.join();
threads_.wait();
throw;
}
}
@@ -53,7 +55,7 @@ public:
~fork_join_pool()
{
stop_threads();
threads_.join();
threads_.wait();
}
private:
@@ -117,7 +119,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_);
@@ -135,16 +137,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()
{
@@ -158,7 +150,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
@@ -172,45 +164,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
template <class Func>
void execute(Func f) const
{
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
{
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,
@@ -289,8 +252,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); });
execution::execute(fork, [=]{ fork_join_sort(begin, begin + n / 2); });
execution::execute(fork, [=]{ fork_join_sort(begin + n / 2, end); });
}
std::inplace_merge(begin, begin + n / 2, end);
}

View File

@@ -11,6 +11,7 @@
#include <queue>
#include <thread>
#include <vector>
#include <cctype>
using boost::asio::execution_context;
using boost::asio::executor_binder;
@@ -19,9 +20,10 @@ using boost::asio::post;
using boost::asio::system_executor;
using boost::asio::use_future;
using boost::asio::use_service;
namespace execution = boost::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:
@@ -54,40 +56,28 @@ private:
};
public:
execution_context& context() const noexcept
execution_context& query(execution::context_t) const
{
return system_executor().context();
return boost::asio::query(system_executor(), execution::context);
}
void on_work_started() const noexcept
execution::blocking_t query(execution::blocking_t) const
{
// This executor doesn't count work.
return execution::blocking.never;
}
void on_work_finished() const noexcept
thread_executor require(execution::blocking_t::never_t) const
{
// This executor doesn't count work.
return *this;
}
template <class Func, class Alloc>
void dispatch(Func&& f, const Alloc& a) const
template <class Func>
void execute(Func f) 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 = use_service<thread_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
{
@@ -291,7 +281,7 @@ void writer(queue_back<std::string> in)
int main()
{
thread_pool pool;
thread_pool pool(1);
auto f = pipeline(reader, filter, bind_executor(pool, upper), writer);
f.wait();

View File

@@ -8,6 +8,7 @@
using boost::asio::dispatch;
using boost::asio::execution_context;
namespace execution = boost::asio::execution;
class priority_scheduler : public execution_context
{
@@ -21,47 +22,20 @@ public:
{
}
priority_scheduler& context() const noexcept
priority_scheduler& query(execution::context_t) const noexcept
{
return context_;
}
void on_work_started() const noexcept
template <class Func>
void execute(Func f) const
{
// This executor doesn't count work. Instead, the scheduler simply runs
// until explicitly stopped.
}
void on_work_finished() const noexcept
{
// This executor doesn't count work. Instead, the scheduler simply runs
// until explicitly stopped.
}
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& a) 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
{
@@ -79,6 +53,12 @@ public:
int priority_;
};
~priority_scheduler() noexcept
{
shutdown();
destroy();
}
executor_type get_executor(int pri = 0) noexcept
{
return executor_type(*const_cast<priority_scheduler*>(this), pri);