feat-debug(thread_pool): log the job and which thread execute it for debugging purposes in case the thread never exit. also log in case a job is scheduled but none of the thread are currently available (#1190)

This commit is contained in:
Quentin E. / iDeath 2023-04-04 23:52:57 +02:00 committed by GitHub
parent e1ce85fd71
commit 626394eca7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 31 additions and 8 deletions

View File

@ -22,6 +22,8 @@ namespace big
LOG(VERBOSE) << "Allocating " << thread_count << " threads in thread pool."; LOG(VERBOSE) << "Allocating " << thread_count << " threads in thread pool.";
this->m_thread_pool.reserve(thread_count); this->m_thread_pool.reserve(thread_count);
m_available_thread_count = thread_count;
for (std::uint32_t i = 0; i < thread_count; i++) for (std::uint32_t i = 0; i < thread_count; i++)
this->m_thread_pool.emplace_back(std::thread(&thread_pool::run, this)); this->m_thread_pool.emplace_back(std::thread(&thread_pool::run, this));
} }
@ -41,13 +43,18 @@ namespace big
m_thread_pool.clear(); m_thread_pool.clear();
} }
void thread_pool::push(std::function<void()> func) void thread_pool::push(std::function<void()> func, std::source_location location)
{ {
if (func) if (func)
{ {
{ {
std::unique_lock lock(this->m_lock); std::unique_lock lock(this->m_lock);
this->m_job_stack.push(std::move(func)); this->m_job_stack.push({func, location});
if (m_available_thread_count < m_job_stack.size())
{
LOG(WARNING) << "thread_pool potentially starved";
}
} }
this->m_data_condition.notify_all(); this->m_data_condition.notify_all();
} }
@ -68,18 +75,26 @@ namespace big
if (this->m_job_stack.empty()) if (this->m_job_stack.empty())
continue; continue;
std::function<void()> job = std::move(this->m_job_stack.top()); thread_pool_job job = this->m_job_stack.top();
this->m_job_stack.pop(); this->m_job_stack.pop();
lock.unlock(); lock.unlock();
m_available_thread_count--;
try try
{ {
std::invoke(std::move(job)); const auto source_file = std::filesystem::path(job.m_source_location.file_name()).filename().string();
LOG(VERBOSE) << "Thread " << std::this_thread::get_id() << " executing " << source_file << ":"
<< job.m_source_location.line();
std::invoke(job.m_func);
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {
LOG(WARNING) << "Exception thrown while executing job in thread:" << std::endl << e.what(); LOG(WARNING) << "Exception thrown while executing job in thread:" << std::endl << e.what();
} }
m_available_thread_count++;
} }
LOG(VERBOSE) << "Thread " << std::this_thread::get_id() << " exiting..."; LOG(VERBOSE) << "Thread " << std::this_thread::get_id() << " exiting...";

View File

@ -2,23 +2,31 @@
namespace big namespace big
{ {
struct thread_pool_job
{
std::function<void()> m_func;
std::source_location m_source_location;
};
class thread_pool class thread_pool
{ {
std::atomic<bool> m_accept_jobs; std::atomic<bool> m_accept_jobs;
std::condition_variable m_data_condition; std::condition_variable m_data_condition;
std::stack<std::function<void()>> m_job_stack; std::stack<thread_pool_job> m_job_stack;
std::mutex m_lock; std::mutex m_lock;
std::vector<std::thread> m_thread_pool; std::vector<std::thread> m_thread_pool;
std::thread m_managing_thread; std::thread m_managing_thread;
std::atomic<size_t> m_available_thread_count;
public: public:
thread_pool(); thread_pool();
~thread_pool(); ~thread_pool();
void destroy(); void destroy();
void push(std::function<void()> func); void push(std::function<void()> func, std::source_location location = std::source_location::current());
private: private:
void create(); void create();