lib:boost
Ceci est une ancienne révision du document !
Compilation sous Windows
git clone https://github.com/boostorg/boost.git git checkout boost-1.69.0 --recurse-submodules # C'est celui dans le dossier boost pas boost\tools\build bootstrap.bat b2 -j4 toolset=msvc-14.0 address-model=64 architecture=x86 threading=multi --build-type=complete variant=debug,release install --prefix=boost.install
Compilation pour Visual Studio 2015 et pour des programmes en 64 bits (address-model
). architecture
vaut x86
que ce soit pour address-model
à 32 ou 64.
Il n'y a pas link
ni runtime-link
de défini. Les deux versions static
et shared
seront compilés.
On génère simultanément la version de release
et debug
.
Nommage de la dll
Exécuteur
L'exécuteur a les caractéristiques suivantes :
- Fonctionnement entre thread, pas entre application via TCP,
- Toujours en fonctionnement. En attente s'il n'a plus de travail à faire.
Entête :
#include <functional> #include <memory> class PriorityScheduler { public: // Classe satisfaisant l'interface Executor. class ExecutorType { public: ExecutorType(PriorityScheduler& ctx, int pri); ~ExecutorType(); ExecutorType(ExecutorType&& other) noexcept; ExecutorType(ExecutorType const& other) = delete; ExecutorType& operator=(ExecutorType&& other) noexcept = delete; ExecutorType& operator=(ExecutorType const& other) = delete; // Pour boost::asio::dispatch PriorityScheduler& context() const noexcept; void add(std::function<void()> f); private: class ExecutorTypeImpl; std::unique_ptr<ExecutorTypeImpl> impl_; }; PriorityScheduler(); ~PriorityScheduler(); ExecutorType get_executor(int pri) noexcept; void run(); void stop(); private: class PrioritySchedulerImpl; std::unique_ptr<PrioritySchedulerImpl> impl_; }; bool operator==(const PriorityScheduler::ExecutorType& a, const PriorityScheduler::ExecutorType& b) noexcept; bool operator!=(const PriorityScheduler::ExecutorType& a, const PriorityScheduler::ExecutorType& b) noexcept; }
Source :
#include "Executeur.h" #include <atomic> #include <boost/asio.hpp> #include <queue> #include <vector> class PriorityScheduler::PrioritySchedulerImpl : public boost::asio::execution_context { public: void run() { std::unique_lock<std::mutex> lock(mutex_); for (;;) { condition_.wait(lock, [&] { return stopped_ || !queue_.empty(); }); if (stopped_) return; auto p(queue_.top()); queue_.pop(); lock.unlock(); p->execute_(p); lock.lock(); } } void stop() { stopped_ = true; condition_.notify_all(); } struct item_base { // Priorité de l'ordre. int priority_; // Pour trier les item ayant le même ordre. std::chrono::high_resolution_clock::time_point timestamp; // Fonction a exécuter dans un wrapper compatible avec // boost::asio::dispatch. std::function<void(std::shared_ptr<item_base>&)> execute_; }; template <class Func> struct item : item_base { item(int pri, Func f) : function_(std::move(f)) { priority_ = pri; execute_ = [](std::shared_ptr<item_base>& p) { Func tmp(std::move(static_cast<item*>(p.get())->function_)); p.reset(); tmp(); }; timestamp = std::chrono::high_resolution_clock::now(); } Func function_; }; // Pour comparer les items et savoir quel sera la prochaine fonction à // exécuter. struct item_comp { bool operator()(const std::shared_ptr<item_base>& a, const std::shared_ptr<item_base>& b) { if (a->priority_ != b->priority_) return a->priority_ < b->priority_; else return a->timestamp > b->timestamp; } }; std::mutex mutex_; std::condition_variable condition_; std::priority_queue<std::shared_ptr<item_base>, std::vector<std::shared_ptr<item_base>>, item_comp> queue_; std::atomic<bool> stopped_ = false; }; class PriorityScheduler::ExecutorType::ExecutorTypeImpl { public: ExecutorTypeImpl(PriorityScheduler& ctx, int pri) noexcept : context_(ctx), priority_(pri) { } ExecutorTypeImpl(ExecutorTypeImpl&& other) noexcept = default; ExecutorTypeImpl(ExecutorTypeImpl const& other) = delete; ExecutorTypeImpl& operator=(ExecutorTypeImpl&& other) noexcept = default; ExecutorTypeImpl& operator=(ExecutorTypeImpl const& other) = delete; // Pour boost::asio::dispatch PriorityScheduler& context() const noexcept { return context_; } // Pour boost::asio::dispatch void on_work_started() const noexcept {} // Pour boost::asio::dispatch void on_work_finished() const noexcept {} // Partout Func est boost::asio::detail::work_dispatcher<void()> template <class Func, class Alloc> void dispatch(Func&& f, const Alloc& a) const { post(std::forward<Func>(f), a); } private: PriorityScheduler& context_; int priority_; template <class Func, class Alloc> void post(Func f, const Alloc& a) const { // On se force à utiliser l'allocateur fournit. auto p(std::allocate_shared< PriorityScheduler::PrioritySchedulerImpl::item<Func>>( typename std::allocator_traits<Alloc>::template rebind_alloc<char>(a), priority_, std::move(f))); // On sécurise seulement queue_. { std::lock_guard<std::mutex> lock(context_.impl_->mutex_); context_.impl_->queue_.push(p); } context_.impl_->condition_.notify_one(); } // Pour boost::asio::dispatch template <class Func, class Alloc> void defer(Func&& f, const Alloc& a) const { post(std::forward<Func>(f), a); } }; // Impl idiome PriorityScheduler::ExecutorType::ExecutorType(PriorityScheduler& ctx, int pri) : impl_(std::make_unique<ExecutorTypeImpl>(ctx, pri)) { } PriorityScheduler::ExecutorType::~ExecutorType() = default; PriorityScheduler::ExecutorType::ExecutorType(ExecutorType&& other) noexcept = default; PriorityScheduler& PriorityScheduler::ExecutorType::context() const noexcept { return impl_->context(); } void PriorityScheduler::ExecutorType::add(std::function<void()> f) { boost::asio::dispatch(*impl_, f); } bool operator==(const PriorityScheduler::ExecutorType& a, const PriorityScheduler::ExecutorType& b) noexcept { return &a.context() == &b.context(); } bool operator!=(const PriorityScheduler::ExecutorType& a, const PriorityScheduler::ExecutorType& b) noexcept { return &a.context() != &b.context(); } PriorityScheduler::PriorityScheduler() : impl_(std::make_unique<PrioritySchedulerImpl>()) { } PriorityScheduler::~PriorityScheduler() = default; PriorityScheduler::ExecutorType PriorityScheduler::get_executor( int pri) noexcept { return PriorityScheduler::ExecutorType(*this, pri); } void PriorityScheduler::run() { impl_->run(); } void PriorityScheduler::stop() { impl_->stop(); }
Utilisation :
#include <atomic> #include <chrono> #include <iostream> #include <string> #include "Executeur.h" std::atomic<int> test = 0; int main() { PriorityScheduler sched; PriorityScheduler::ExecutorType&& nulle = sched.get_executor(-1); PriorityScheduler::ExecutorType&& low = sched.get_executor(0); PriorityScheduler::ExecutorType&& med = sched.get_executor(1); PriorityScheduler::ExecutorType&& high = sched.get_executor(2); med.add([] { std::cout << "2\n"; }); low.add([] { std::cout << "1\n"; }); med.add([] { std::cout << "22\n"; }); low.add([] { std::cout << "11\n"; }); high.add([] { std::cout << "3\n"; }); high.add([] { std::cout << "33\n"; }); high.add([] { std::cout << "333\n"; }); nulle.add([&sched] { sched.stop(); }); std::thread t([&sched] { sched.run(); }); t.join(); }
Rendu :
3 33 333 2 22 1 11
lib/boost.1573576881.txt.gz · Dernière modification : 2019/11/12 17:41 de root