優先度付きio_service

io_serviceに優先度付けてpost出来ないもんかなぁと思ってたんですが、
strandの実装を真似ればいいんだ、と気が付きました。

#include <queue>
#include <map>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/foreach.hpp>
#include <boost/thread.hpp>

class priority{
  boost::asio::io_service &io;

  typedef boost::function<void ()> CompletionHandler;
  typedef std::queue<const CompletionHandler> CompletionHandlerArray;
  typedef std::map<int, CompletionHandlerArray> CompletionHandlerArrayMap;
  CompletionHandlerArrayMap priorityhandler;
  boost::mutex mutex;

  void worker(){
    boost::mutex::scoped_lock lk(mutex);
    BOOST_FOREACH(CompletionHandlerArrayMap::reference ref, priorityhandler){
      if ( ! ref.second.empty()){
        CompletionHandler front = ref.second.front();
        ref.second.pop();
        lk.unlock();
        front();
        break;
      }
    }
  }

public:
  priority(boost::asio::io_service &io):io(io),priorityhandler(){}
  ~priority(){}

  void post(int p, const CompletionHandler &handler){
    boost::mutex::scoped_lock lk(mutex);
    priorityhandler[p].push(handler);
    io.post(boost::bind(&priority::worker, this));
  }
};

使い方はこんな感じ

int main(){
  boost::asio::io_service io;
  priority pri(io);

  for (int i = 0; i < 100; i++){
    int p = i % 5;
    pri.post(p, 
      [=](){
        std::cout << "priority:" << p << " number:" << i << std::endl;
        boost::this_thread::sleep(boost::posix_time::millisec(10));
      }
    );
  }

  io.run();

  return 0;
}