util/threadpool: Show warnings for uncaught exceptions

Tasks should not leak exceptions, so it is better if we actually log them instead of silently ignoring them.
This commit is contained in:
Michael Fabian 'Xaymar' Dirks 2020-07-27 21:33:11 +02:00
parent 2fb901278f
commit d883f66fa0
2 changed files with 18 additions and 5 deletions

View File

@ -18,12 +18,15 @@
*/ */
#include "util-threadpool.hpp" #include "util-threadpool.hpp"
#include "common.hpp"
#include <cstddef> #include <cstddef>
#define LOCAL_PREFIX "<util::threadpool> "
// Most Tasks likely wait for IO, so we can use that time for other tasks. // Most Tasks likely wait for IO, so we can use that time for other tasks.
#define CONCURRENCY_MULTIPLIER 2 #define CONCURRENCY_MULTIPLIER 2
util::threadpool::threadpool() : _workers(), _worker_stop(false), _tasks(), _tasks_lock(), _tasks_cv() util::threadpool::threadpool() : _workers(), _worker_stop(false), _worker_idx(0), _tasks(), _tasks_lock(), _tasks_cv()
{ {
std::size_t concurrency = static_cast<size_t>(std::thread::hardware_concurrency() * CONCURRENCY_MULTIPLIER); std::size_t concurrency = static_cast<size_t>(std::thread::hardware_concurrency() * CONCURRENCY_MULTIPLIER);
for (std::size_t n = 0; n < concurrency; n++) { for (std::size_t n = 0; n < concurrency; n++) {
@ -63,7 +66,8 @@ void util::threadpool::pop(std::shared_ptr<::util::threadpool::task> work)
void util::threadpool::work() void util::threadpool::work()
{ {
static thread_local std::shared_ptr<util::threadpool::task> local_work{}; std::shared_ptr<util::threadpool::task> local_work{};
uint32_t local_number = _worker_idx.fetch_add(1);
while (!_worker_stop) { while (!_worker_stop) {
// Wait for more work, or immediately continue if there is still work to do. // Wait for more work, or immediately continue if there is still work to do.
@ -88,7 +92,7 @@ void util::threadpool::work()
} }
// If the task was killed, skip everything again. // If the task was killed, skip everything again.
if (local_work->_is_dead.load()) { if (local_work->_is_dead) {
continue; continue;
} }
@ -97,13 +101,21 @@ void util::threadpool::work()
try { try {
local_work->_callback(local_work->_data); local_work->_callback(local_work->_data);
} catch (std::exception const& ex) { } catch (std::exception const& ex) {
} catch (...) { // This does not catch unrecoverable exceptions, or exceptions that went through C code. DLOG_WARNING(LOCAL_PREFIX "Worker %lX caught exception from task (%tX, %tX) with message: %s",
local_number, local_work->_callback.target<ptrdiff_t>(),
reinterpret_cast<ptrdiff_t>(local_work->_data.get()), ex.what());
} catch (...) {
DLOG_WARNING(LOCAL_PREFIX "Worker %lX caught exception of unknown type from task (%tX, %tX).",
local_number, local_work->_callback.target<ptrdiff_t>(),
reinterpret_cast<ptrdiff_t>(local_work->_data.get()));
} }
} }
} }
_worker_idx.fetch_sub(1);
} }
util::threadpool::task::task() {} util::threadpool::task::task() {}
util::threadpool::task::task(threadpool_callback_t fn, threadpool_data_t dt) : _callback(fn), _data(dt), _is_dead(false) util::threadpool::task::task(threadpool_callback_t fn, threadpool_data_t dt) : _is_dead(false), _callback(fn), _data(dt)
{} {}

View File

@ -49,6 +49,7 @@ namespace util {
private: private:
std::list<std::thread> _workers; std::list<std::thread> _workers;
std::atomic_bool _worker_stop; std::atomic_bool _worker_stop;
std::atomic<uint32_t> _worker_idx;
std::list<std::shared_ptr<::util::threadpool::task>> _tasks; std::list<std::shared_ptr<::util::threadpool::task>> _tasks;
std::mutex _tasks_lock; std::mutex _tasks_lock;
std::condition_variable _tasks_cv; std::condition_variable _tasks_cv;