//===--------------------- TaskPool.cpp -------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "lldb/Utility/TaskPool.h" namespace { class TaskPoolImpl { public: static TaskPoolImpl &GetInstance(); void AddTask(std::function &&task_fn); private: TaskPoolImpl(); static void Worker(TaskPoolImpl *pool); std::queue> m_tasks; std::mutex m_tasks_mutex; uint32_t m_thread_count; }; } // end of anonymous namespace TaskPoolImpl &TaskPoolImpl::GetInstance() { static TaskPoolImpl g_task_pool_impl; return g_task_pool_impl; } void TaskPool::AddTaskImpl(std::function &&task_fn) { TaskPoolImpl::GetInstance().AddTask(std::move(task_fn)); } TaskPoolImpl::TaskPoolImpl() : m_thread_count(0) {} void TaskPoolImpl::AddTask(std::function &&task_fn) { static const uint32_t max_threads = std::thread::hardware_concurrency(); std::unique_lock lock(m_tasks_mutex); m_tasks.emplace(std::move(task_fn)); if (m_thread_count < max_threads) { m_thread_count++; // Note that this detach call needs to happen with the m_tasks_mutex held. // This prevents the thread // from exiting prematurely and triggering a linux libc bug // (https://sourceware.org/bugzilla/show_bug.cgi?id=19951). std::thread(Worker, this).detach(); } } void TaskPoolImpl::Worker(TaskPoolImpl *pool) { while (true) { std::unique_lock lock(pool->m_tasks_mutex); if (pool->m_tasks.empty()) { pool->m_thread_count--; break; } std::function f = pool->m_tasks.front(); pool->m_tasks.pop(); lock.unlock(); f(); } }