Пример пула потоков 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
сам может выйти из цикла таким способом - например, в деструкторе.