Outils pour utilisateurs

Outils du site


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