Boost logo

Boost :

From: Christopher Kohlhoff (chris_at_[hidden])
Date: 2007-03-12 09:30:39


Hi Braddock,

On Fri, 09 Mar 2007 09:05:42 -0500, "Braddock Gaskill"
<braddock_at_[hidden]> said:
> The ability to use a future with the asio::io_service in particular would
> be quite powerful.

I've attached a quick and dirty futures implementation that I wrote last
year to demonstrate how futures and asio might fit together. Unlike the
various futures proposals that are around, I prefer to keep the producer
and consumer interfaces separate. Hence I have promise<T> (producer
interface) and future<T> (consumer interface) -- these names are
borrowed from the Alice programming language.

Cheers,
Chris


#ifndef FUTURE_HPP
#define FUTURE_HPP

#include <memory>
#include <stdexcept>
#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>

namespace detail {

template <typename T>
class return_value
{
public:
  class exception_holder_base
  {
  public:
    virtual ~exception_holder_base()
    {
    }

    virtual void raise() const = 0;
  };

  template <typename E>
  class exception_holder :
    public exception_holder_base
  {
  public:
    exception_holder(E e)
      : e_(e)
    {
    }

    virtual void raise() const
    {
      throw e_;
    }

  private:
    E e_;
  };

  T get() const
  {
    boost::mutex::scoped_lock lock(mutex_);
    while (!value_.get() && !exception_.get())
      condition_.wait(lock);
    if (exception_.get())
      exception_->raise();
    return *value_;
  }

  void set(T t)
  {
    boost::mutex::scoped_lock lock(mutex_);
    if (value_.get() == 0 && exception_.get() == 0)
    {
      value_.reset(new T(t));
      condition_.notify_all();
    }
  }

  template <typename E>
  void fail(E e)
  {
    boost::mutex::scoped_lock lock(mutex_);
    if (value_.get() == 0 && exception_.get() == 0)
    {
      exception_.reset(new exception_holder<E>(e));
      condition_.notify_all();
    }
  }

private:
  mutable boost::mutex mutex_;
  mutable boost::condition condition_;
  std::auto_ptr<T> value_;
  std::auto_ptr<exception_holder_base> exception_;
};

} // namespace detail

template <typename T>
class future;

template <typename T>
class promise
{
public:
  promise()
    : return_value_(new detail::return_value<T>)
  {
  }

  void operator()(T t) // Fulfil
  {
    return_value_->set(t);
  }

  template <typename E>
  void fail(E e)
  {
    return_value_->fail(e);
  }

private:
  friend class future<T>;
  boost::shared_ptr<detail::return_value<T> > return_value_;
};

template <typename T>
class future
{
private:
public:
  future(promise<T>& p)
    : return_value_(p.return_value_)
  {
  }

  T operator()() const // Await
  {
    return return_value_->get();
  }

private:
  boost::shared_ptr<detail::return_value<T> > return_value_;
};

#endif // FUTURE_HPP

#include <iostream>
#include <ostream>
#include <string>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include "future.hpp"

class Resolver
{
public:
  Resolver() :
    io_service_(),
    work_(io_service_),
    resolver_(io_service_),
    thread_(boost::bind(&boost::asio::io_service::run, &io_service_))
  {
  }

  ~Resolver()
  {
    io_service_.stop();
    thread_.join();
  }

  future<std::string> resolve(std::string host_name)
  {
    promise<std::string> result;
    boost::asio::ip::tcp::resolver::query query(host_name, "0");
    resolver_.async_resolve(query,
        boost::bind(&Resolver::handle_resolve, this, _1, _2, result));
    return result;
  }

private:
  void handle_resolve(boost::system::error_code ec,
      boost::asio::ip::tcp::resolver::iterator iterator,
      promise<std::string> result)
  {
    if (ec)
      result.fail(boost::system::system_error(ec));
    else
      result(iterator->endpoint().address().to_string());
  }

  boost::asio::io_service io_service_;
  boost::asio::io_service::work work_;
  boost::asio::ip::tcp::resolver resolver_;
  boost::thread thread_;
};

int main()
{
  Resolver resolver;
  future<std::string> result = resolver.resolve("www.boost.org");
  std::cout << result() << "\n";
  return 0;
}


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk