Boost ASIO using a member function as handler



In the fourth step of the official Boost ASIO tutorial, a class method in used as handler instead of the free function. See the previous post for my version that uses free function - or a lambda function. Here I present my refactored code that uses less Boost and more C++ standard stuff.

All the relevant code is now in the class Printer, so the function in the main thread gets much simpler:
Printer printer(io);
io.run();
Where io is a boost::asio::io_context object - previously known as io_service.

Here is the Printer class:
class Printer
{
private:
 ba::system_timer timer_;
 int count_;
public:
 Printer(ba::io_context& io) : timer_(io, sc::milliseconds(500)), count_(0)  // 1
 {
  timer_.async_wait(std::bind(&Printer::print, this));
 }

 ~Printer()  // 2
 {
  std::cout << "final count is " << count_ << std::endl;
 }

 void print()  // 3
 {
  if (count_ < 5)
  {
   std::cout << count_++ << ' ';
   timer_.expires_at(timer_.expiry() + sc::milliseconds(500));
   timer_.async_wait(std::bind(&Printer::print, this));
  }
 }
};
1. The constructor initializes the member variables and then asks ASIO to set an asychronous wait on the timer, passing as handler the member function print() of this object.
2. The dtor will print the final counter value.
3. Same old print() function, but now is a method of Printer, so it could freely access its data members.

This approach looks cleaner of the free function one. Still, we need to keep in our mind the fact that timer_, count_ (and cout) are seen by two different threads, and this could lead to concurrency problems, that could be solved using mutexes and locks, as I have shown in a previous spoilery post, or using the ASIO concept of strand, as we'll see in the next post.

No comments:

Post a Comment