zoukankan      html  css  js  c++  java
  • Timer.5

     

    This tutorial demonstrates the use of the boost::asio::strand class to synchronise callback handlers in a multithreaded program.

    The previous four tutorials avoided the issue of handler synchronisation by calling the boost::asio::io_service::run() function from one thread only. As you already know, the asio library provides a guarantee that callback handlers will only be called from threads that are currently calling boost::asio::io_service::run(). Consequently, calling boost::asio::io_service::run() from only one thread ensures that callback handlers cannot run concurrently.

    The single threaded approach is usually the best place to start when developing applications using asio. The downside is the limitations it places on programs, particularly servers, including:

    • Poor responsiveness when handlers can take a long time to complete.
    • An inability to scale on multiprocessor systems.

    If you find yourself running into these limitations, an alternative approach is to have a pool of threads calling boost::asio::io_service::run(). However, as this allows handlers to execute concurrently, we need a method of synchronisation when handlers might be accessing a shared, thread-unsafe resource.

    #include <iostream>
    #include <boost/asio.hpp>
    #include <boost/thread.hpp>
    #include <boost/bind.hpp>
    #include <boost/date_time/posix_time/posix_time.hpp>
    

    We start by defining a class called printer, similar to the class in the previous tutorial. This class will extend the previous tutorial by running two timers in parallel.

    class printer
    {
    public:
    

    In addition to initialising a pair of boost::asio::deadline_timer members, the constructor initialises the strand_ member, an object of type boost::asio::strand.

    An boost::asio::strand guarantees that, for those handlers that are dispatched through it, an executing handler will be allowed to complete before the next one is started. This is guaranteed irrespective of the number of threads that are calling boost::asio::io_service::run(). Of course, the handlers may still execute concurrently with other handlers that were not dispatched through an boost::asio::strand, or were dispatched through a different boost::asio::strand object.

      printer(boost::asio::io_service& io)
        : strand_(io),
          timer1_(io, boost::posix_time::seconds(1)),
          timer2_(io, boost::posix_time::seconds(1)),
          count_(0)
      {
    

    When initiating the asynchronous operations, each callback handler is "wrapped" using the boost::asio::strand object. The boost::asio::strand::wrap() function returns a new handler that automatically dispatches its contained handler through the boost::asio::strand object. By wrapping the handlers using the same boost::asio::strand, we are ensuring that they cannot execute concurrently.

        timer1_.async_wait(strand_.wrap(boost::bind(&printer::print1, this)));
        timer2_.async_wait(strand_.wrap(boost::bind(&printer::print2, this)));
      }
    
      ~printer()
      {
        std::cout << "Final count is " << count_ << "
    ";
      }
    

    In a multithreaded program, the handlers for asynchronous operations should be synchronised if they access shared resources. In this tutorial, the shared resources used by the handlers (print1 and print2) are std::cout and the count_ data member.

      void print1()
      {
        if (count_ < 10)
        {
          std::cout << "Timer 1: " << count_ << "
    ";
          ++count_;
    
          timer1_.expires_at(timer1_.expires_at() + boost::posix_time::seconds(1));
          timer1_.async_wait(strand_.wrap(boost::bind(&printer::print1, this)));
        }
      }
    
      void print2()
      {
        if (count_ < 10)
        {
          std::cout << "Timer 2: " << count_ << "
    ";
          ++count_;
    
          timer2_.expires_at(timer2_.expires_at() + boost::posix_time::seconds(1));
          timer2_.async_wait(strand_.wrap(boost::bind(&printer::print2, this)));
        }
      }
    
    private:
      boost::asio::strand strand_;
      boost::asio::deadline_timer timer1_;
      boost::asio::deadline_timer timer2_;
      int count_;
    };
    

    The main function now causes boost::asio::io_service::run() to be called from two threads: the main thread and one additional thread. This is accomplished using an boost::thread object.

    Just as it would with a call from a single thread, concurrent calls to boost::asio::io_service::run() will continue to execute while there is "work" left to do. The background thread will not exit until all asynchronous operations have completed.

    int main()
    {
      boost::asio::io_service io;
      printer p(io);
      boost::thread t(boost::bind(&boost::asio::io_service::run, &io));
      io.run();
      t.join();
    
      return 0;
    }
    

    See the full source listing

  • 相关阅读:
    使用IDEA模拟git命令使用的常见场景
    解决 No converter found for return value of type: class java.util.ArrayList
    Connections could not be acquired from the underlying database! ### The error may exist in mapper/BookMapper.xml
    There is no PasswordEncoder mapped for the id "null"
    The server time zone value '�й���׼ʱ��' is unrecognized or represents more than one time zone
    MySQL错误:2003-Can't connect to MySQL server on 'localhost'(10061 "unknown error")
    镜像源
    读书笔记 Week5 2018-4-5
    [第五周课后作业] 软件创新分析
    C#入门学习笔记
  • 原文地址:https://www.cnblogs.com/lvdongjie/p/4461754.html
Copyright © 2011-2022 走看看