Setting limit on post queue size with Boost Asio?

后端 未结 4 1573
慢半拍i
慢半拍i 2021-02-20 18:09

I\'m using boost::asio::io_service as a basic thread pool. Some threads get added to io_service, the main thread starts posting handlers, the worker threads start r

4条回答
  •  悲&欢浪女
    2021-02-20 18:44

    You can wrap your lambda in another lambda which would take care of counting the "in-progress" tasks, and then wait before posting if there are too many in-progress tasks.

    Example:

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    class ThreadPool {
      using asio_worker = std::unique_ptr;
      boost::asio::io_service service;
      asio_worker service_worker;
      std::vector grp;
      std::atomic inProgress = 0;
      std::mutex mtx;
      std::condition_variable busy;
    public:
      ThreadPool(int threads) : service(), service_worker(new asio_worker::element_type(service)) {
        for (int i = 0; i < threads; ++i) {
          grp.emplace_back([this] { service.run(); });
        }
      }
    
      template
      void enqueue(F && f) {
        std::unique_lock lock(mtx);
        // limit queue depth = number of threads
        while (inProgress >= grp.size()) {
          busy.wait(lock);
        }
        inProgress++;
        service.post([this, f = std::forward(f)]{
          try {
            f();
          }
          catch (...) {
            inProgress--;
            busy.notify_one();
            throw;
          }
          inProgress--;
          busy.notify_one();
        });
      }
    
      ~ThreadPool() {
        service_worker.reset();
        for (auto& t : grp)
          if (t.joinable())
            t.join();
        service.stop();
      }
    };
    
    int main() {
      std::unique_ptr pool(new ThreadPool(4));
      for (int i = 1; i <= 20; ++i) {
        pool->enqueue([i] {
          std::string s("Hello from task ");
          s += std::to_string(i) + "\n";
          std::cout << s;
          std::this_thread::sleep_for(std::chrono::seconds(1));
        });
      }
      std::cout << "All tasks queued.\n";
      pool.reset(); // wait for all tasks to complete
      std::cout << "Done.\n";
    }
    

    Output:

    Hello from task 3
    Hello from task 4
    Hello from task 2
    Hello from task 1
    Hello from task 5
    Hello from task 7
    Hello from task 6
    Hello from task 8
    Hello from task 9
    Hello from task 10
    Hello from task 11
    Hello from task 12
    Hello from task 13
    Hello from task 14
    Hello from task 15
    Hello from task 16
    Hello from task 17
    Hello from task 18
    All tasks queued.
    Hello from task 19
    Hello from task 20
    Done.
    

提交回复
热议问题