LCOV - code coverage report
Current view: top level - src/core/async - thread_pool.cpp (source / functions) Hit Total Coverage
Test: libopenmodelviewer coverage Lines: 52 59 88.1 %
Date: 2025-07-03 20:26:48 Functions: 10 12 83.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //
       2             : // Copyright 2024 OpenModelViewer Authors
       3             : // 
       4             : // Licensed under the Apache License, Version 2.0 (the "License");
       5             : // you may not use this file except in compliance with the License.
       6             : // You may obtain a copy of the License at
       7             : // 
       8             : //     http://www.apache.org/licenses/LICENSE-2.0
       9             : // 
      10             : // Unless required by applicable law or agreed to in writing, software
      11             : // distributed under the License is distributed on an "AS IS" BASIS,
      12             : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13             : // See the License for the specific language governing permissions and
      14             : // limitations under the License.
      15             : //
      16             : 
      17             : #include "openmodelviewer/core/async/thread_pool.hpp"
      18             : 
      19             : #include <algorithm>
      20             : 
      21             : namespace openmodelviewer::core::async
      22             : {
      23          63 :         ThreadPool::ThreadPool(size_t poolSize) :
      24          63 :                 m_poolSize(poolSize)
      25             :         {
      26          63 :                 m_running = false;
      27          63 :         }
      28             : 
      29         124 :         ThreadPool::~ThreadPool()
      30             :         {
      31          63 :                 this->stop();
      32         124 :         }
      33             : 
      34          49 :         bool ThreadPool::start()
      35             :         {
      36          49 :                 if (m_running.load() || m_poolSize == 0)
      37             :                 {
      38           0 :                         return false;
      39             :                 }
      40             : 
      41          49 :                 m_running = true;
      42             : 
      43         146 :                 for (size_t i = 0; i < m_poolSize; i++)
      44             :                 {
      45          97 :                         m_workers.emplace_back(
      46          97 :                                 [this]()
      47             :                                 {
      48          97 :                                         this->workLoop();
      49          97 :                                 }
      50             :                         );
      51             :                 }
      52             : 
      53          49 :                 return true;
      54             :         }
      55             : 
      56         112 :         void ThreadPool::stop()
      57             :         {
      58         112 :                 if (!m_running.load())
      59             :                 {
      60          63 :                         return;
      61             :                 }
      62             : 
      63          49 :                 m_running = false;
      64             : 
      65             :                 {
      66          49 :                         std::lock_guard<std::mutex> lock(m_mutex);
      67          49 :                         m_condition.notify_all();
      68          49 :                 }
      69             : 
      70         146 :                 for (auto& worker : m_workers)
      71             :                 {
      72          97 :                         if (worker.joinable())
      73             :                         {
      74          97 :                                 worker.join();
      75             :                         }
      76             :                 }
      77             : 
      78          49 :                 m_workers.clear();
      79             :         }
      80             : 
      81         181 :         bool ThreadPool::isRunning() const noexcept
      82             :         {
      83         181 :                 return m_running.load();
      84             :         }
      85             : 
      86          59 :         size_t ThreadPool::computeOptimalPoolSize(size_t reserved)
      87             :         {
      88          59 :                 const auto hc = std::thread::hardware_concurrency();
      89             :                 
      90          59 :                 if (hc <= (2 + reserved))
      91             :                 {
      92           3 :                         return 1;
      93             :                 }
      94             : 
      95          56 :                 return static_cast<size_t>(hc - (2 + reserved));
      96             :         }
      97             : 
      98          97 :         void ThreadPool::workLoop()
      99             :         {
     100         186 :                 while (m_running.load())
     101             :                 {
     102         162 :                         std::unique_lock<std::mutex> ulock(m_mutex);
     103         168 :                         m_condition.wait(ulock,
     104         476 :                                 [this]()
     105             :                                 {
     106         283 :                                         return (!this->m_tasks.empty() || !this->m_running.load());
     107             :                                 }
     108             :                         );
     109             : 
     110         168 :                         if (!m_running.load() && m_tasks.empty())
     111             :                         {
     112          78 :                                 return;
     113             :                         }
     114             : 
     115          90 :                         std::unique_ptr<ITask> task = std::move(m_tasks.front());
     116             :                         
     117          90 :                         m_tasks.pop();
     118          90 :                         ulock.unlock();
     119             : 
     120          90 :                         if (task)
     121             :                         {
     122          90 :                                 m_activeTasks.fetch_add(1, std::memory_order_relaxed);
     123          90 :                                 task->execute();
     124          83 :                                 m_activeTasks.fetch_sub(1, std::memory_order_relaxed);
     125             : 
     126         166 :                                 if (m_activeTasks.load() == 0 && m_tasks.empty())
     127             :                                 {
     128          38 :                                         m_idleCondition.notify_all();
     129             :                                 }
     130             :                         }
     131         162 :                 }
     132             :         }
     133             : 
     134           0 :         void ThreadPool::waitIdle()
     135             :         {
     136           0 :                 std::unique_lock<std::mutex> lock(m_mutex);
     137           0 :                 m_idleCondition.wait(lock,
     138           0 :                         [this]
     139             :                         {
     140           0 :                                 return m_tasks.empty() && m_activeTasks.load() == 0;
     141             :                         }
     142             :                 );
     143           0 :         }
     144             : }

Generated by: LCOV version 1.14