dncurrency/nano/lib/thread_runner.cpp
2024-12-17 18:49:24 +01:00

109 lines
2.5 KiB
C++

#include <nano/lib/thread_runner.hpp>
#include <nano/lib/timer.hpp>
#include <iostream>
#include <thread>
/*
* thread_runner
*/
nano::thread_runner::thread_runner (std::shared_ptr<asio::io_context> io_ctx_a, nano::logger & logger_a, unsigned num_threads_a, const nano::thread_role::name thread_role_a) :
num_threads{ num_threads_a },
role{ thread_role_a },
logger{ logger_a },
io_ctx{ std::move (io_ctx_a) },
io_guard{ asio::make_work_guard (*io_ctx) }
{
debug_assert (io_ctx != nullptr);
start ();
}
nano::thread_runner::~thread_runner ()
{
join ();
}
void nano::thread_runner::start ()
{
logger.debug (nano::log::type::thread_runner, "Starting threads: {} ({})", num_threads, to_string (role));
for (auto i = 0; i < num_threads; ++i)
{
threads.emplace_back (nano::thread_attributes::get_default (), [this] () {
nano::thread_role::set (role);
try
{
run ();
}
catch (std::exception const & ex)
{
logger.critical (nano::log::type::thread_runner, "Error: {}", ex.what ());
#ifndef NDEBUG
throw; // Re-throw to debugger in debug mode
#endif
}
catch (...)
{
logger.critical (nano::log::type::thread_runner, "Unknown error");
#ifndef NDEBUG
throw; // Re-throw to debugger in debug mode
#endif
}
});
}
}
void nano::thread_runner::join ()
{
io_guard.reset ();
for (auto & thread : threads)
{
if (thread.joinable ())
{
logger.debug (nano::log::type::thread_runner, "Joining thread: {}", fmt::streamed (thread.get_id ()));
thread.join ();
}
}
threads.clear ();
logger.debug (nano::log::type::thread_runner, "Stopped all threads ({})", to_string (role));
io_ctx.reset (); // Release shared_ptr to io_context
}
void nano::thread_runner::abort ()
{
release_assert (io_ctx != nullptr);
io_ctx->stop ();
}
void nano::thread_runner::run ()
{
if constexpr (nano::asio_handler_tracking_threshold () == 0)
{
io_ctx->run ();
}
else
{
nano::timer<> timer;
timer.start ();
while (true)
{
timer.restart ();
// Run at most 1 completion handler and record the time it took to complete (non-blocking)
auto count = io_ctx->poll_one ();
if (count == 1 && timer.since_start ().count () >= nano::asio_handler_tracking_threshold ())
{
logger.warn (nano::log::type::system, "Async handler processing took too long: {}ms", timer.since_start ().count ());
}
// Sleep for a bit to give more time slices to other threads
std::this_thread::sleep_for (std::chrono::milliseconds (5));
std::this_thread::yield ();
}
}
}