Пример пула потоков C++11 с ошибкой

Ниже приведен код, демонстрирующий простую и короткую реализацию пула потоков.

Код вдохновлен этим постом.

Я собираю это с clang++ -std=c++11 threadpool.cpp -o threadpool -lpthread

При исполнении я получил следующее:

./threadpool 
terminate called without an active exception

Как я вижу, проблема выходит из строя pool_t::pop() и его бесконечный цикл.

У меня вопрос, как элегантно выйти из цикла?

забытый код - мои извинения -

#include <vector>
#include <queue>
#include <thread>
#include <mutex>
#include <functional>
#include <condition_variable>

struct tasks_t
{
  std::queue<std::function<void()>> queue;

  std::mutex mutex;
};

struct threads_t
{
  std::vector<std::thread> vector;

  std::condition_variable condition;
};

struct pool_t
{
  tasks_t tasks;

  threads_t threads;

  void pop()
  {
    while(true)
    {
      std::function<void()> task;
      {
        std::unique_lock<std::mutex> lock(tasks.mutex);

        threads.condition.wait(lock,[this]{return !tasks.queue.empty();});

        task = tasks.queue.front();

        tasks.queue.pop();
      }
      task();
    }
  }

  void push(std::function<void()> function)
  {
    {
      std::unique_lock<std::mutex> lock(tasks.mutex);

      tasks.queue.push(function);
    }
    threads.condition.notify_one();
  }

  void start()
  {
    for (int i=0,j=std::thread::hardware_concurrency(); i!=j; ++i)
    {
      threads.vector.push_back(std::thread(&pool_t::pop,this));
    }
  }
};

#include <chrono>
#include <iostream>

std::function<void()> t0 = []
{
  std::cout << "t0" << std::endl;
  std::this_thread::sleep_for(std::chrono::seconds(1));
  return;
};

std::function<void()> t1 = []
{
  std::cout << "t1" << std::endl;
  std::this_thread::sleep_for(std::chrono::seconds(2));
  return;
};

int main()
{
  pool_t pool;

  pool.start();

  pool.push(t0);

  pool.push(t1);
}

1 ответ

В таком случае проще всего часто ставить задачу в очередь, которая просто генерирует исключение определенного типа, которое может быть перехвачено и обработано...

struct pool_t {
  class quit_exception {};
  tasks_t tasks;
  threads_t threads;

  void pop ()
  {
    while (true) {
      std::function<void()> task;
      {
        std::unique_lock<std::mutex> lock(tasks.mutex);
        threads.condition.wait(lock, [this]{ return !tasks.queue.empty(); });
        task = tasks.queue.front();
        tasks.queue.pop();
      }
      try {
        task();
      }
      catch (quit_exception &ex) {
        return;
      }
    }
  }

Когда вам нужно вырваться из цикла просто сделайте...

pool.push([](){ throw pool::quit_exception(); });

В зависимости от точного использования вы можете сделать quit_exception частный тип, так что только pool_t сам может выйти из цикла таким способом - например, в деструкторе.

Другие вопросы по тегам