使用Boost Asio设置发布队列大小的限制?

时间:2012-07-26 22:46:08

标签: c++ threadpool boost-asio

我使用boost::asio::io_service作为基本线程池。一些线程被添加到io_service,主线程开始发布处理程序,工作线程开始运行处理程序,一切都完成。到现在为止还挺好;我对单线程代码有了很好的加速。

然而,主线程有数以百万计的东西要发布。它只是继续发布它们,比工作线程可以处理它们快得多。我没有达到内存限制,但是将这么多内容排入队列仍然有些愚蠢。我想要做的是处理程序队列具有固定大小,并且如果队列已满,则使用post()块。

我在Boost ASIO文档中没有看到任何选项。这可能吗?

4 个答案:

答案 0 :(得分:2)

我正在使用信号量来修复处理程序队列大小。以下代码说明了此解决方案:

void Schedule(boost::function<void()> function)
{
    semaphore.wait();
    io_service.post(boost::bind(&TaskWrapper, function));
}

void TaskWrapper(boost::function<void()> &function)
{
    function();
    semaphore.post();
}

答案 1 :(得分:1)

您可以将lambda包装在另一个lambda中,该lambda将负责计算“正在进行中”的任务,然后在发布之前等待正在进行的任务太多。

示例:

#include <atomic>
#include <chrono>
#include <future>
#include <iostream>
#include <mutex>
#include <thread>
#include <vector>
#include <boost/asio.hpp>

class ThreadPool {
  using asio_worker = std::unique_ptr<boost::asio::io_service::work>;
  boost::asio::io_service service;
  asio_worker service_worker;
  std::vector<std::thread> grp;
  std::atomic<int> 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<typename F>
  void enqueue(F && f) {
    std::unique_lock<std::mutex> lock(mtx);
    // limit queue depth = number of threads
    while (inProgress >= grp.size()) {
      busy.wait(lock);
    }
    inProgress++;
    service.post([this, f = std::forward<F>(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<ThreadPool> 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";
}

输出:

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.

答案 2 :(得分:0)

您可以使用strand对象来放置事件并在主体中延迟吗?所有工作发布后,您的计划是否退出?如果是这样,您可以使用工作对象,这将使您更好地控制您的io_service何时停止。

你总是可以主要检查线程的状态并让它等待,直到一个变得空闲或类似的东西。

//链接

http://www.boost.org/doc/libs/1_40_0/doc/html/boost_asio/reference/io_service__strand.html

http://www.boost.org/doc/libs/1_40_0/doc/html/boost_asio/reference/io_service.html

//example from the second link
boost::asio::io_service io_service;
boost::asio::io_service::work work(io_service);

希望这会有所帮助。

答案 3 :(得分:0)

也许尝试降低主线程的优先级,这样一旦工作线程忙,他们就会使主线程和系统自我限制。