1 /* 2 * (C) 2019 Jack Lloyd 3 * 4 * Botan is released under the Simplified BSD License (see license.txt) 5 */ 6 7 #include <botan/internal/thread_pool.h> 8 #include <botan/internal/os_utils.h> 9 #include <botan/exceptn.h> 10 #include <thread> 11 12 namespace Botan { 13 14 //static global_instance()15Thread_Pool& Thread_Pool::global_instance() 16 { 17 static Thread_Pool g_thread_pool(OS::read_env_variable_sz("BOTAN_THREAD_POOL_SIZE")); 18 return g_thread_pool; 19 } 20 Thread_Pool(size_t pool_size)21Thread_Pool::Thread_Pool(size_t pool_size) 22 { 23 if(pool_size == 0) 24 { 25 pool_size = OS::get_cpu_available(); 26 27 /* 28 * For large machines don't create too many threads, unless 29 * explicitly asked to by the caller. 30 */ 31 if(pool_size > 16) 32 pool_size = 16; 33 } 34 35 if(pool_size <= 1) 36 pool_size = 2; 37 38 m_shutdown = false; 39 40 for(size_t i = 0; i != pool_size; ++i) 41 { 42 m_workers.push_back(std::thread(&Thread_Pool::worker_thread, this)); 43 } 44 } 45 shutdown()46void Thread_Pool::shutdown() 47 { 48 { 49 std::unique_lock<std::mutex> lock(m_mutex); 50 51 if(m_shutdown == true) 52 return; 53 54 m_shutdown = true; 55 56 m_more_tasks.notify_all(); 57 } 58 59 for(auto&& thread : m_workers) 60 { 61 thread.join(); 62 } 63 m_workers.clear(); 64 } 65 queue_thunk(std::function<void ()> fn)66void Thread_Pool::queue_thunk(std::function<void ()> fn) 67 { 68 std::unique_lock<std::mutex> lock(m_mutex); 69 70 if(m_shutdown) 71 throw Invalid_State("Cannot add work after thread pool has shut down"); 72 73 m_tasks.push_back(fn); 74 m_more_tasks.notify_one(); 75 } 76 worker_thread()77void Thread_Pool::worker_thread() 78 { 79 for(;;) 80 { 81 std::function<void()> task; 82 83 { 84 std::unique_lock<std::mutex> lock(m_mutex); 85 m_more_tasks.wait(lock, [this]{ return m_shutdown || !m_tasks.empty(); }); 86 87 if(m_tasks.empty()) 88 { 89 if(m_shutdown) 90 return; 91 else 92 continue; 93 } 94 95 task = m_tasks.front(); 96 m_tasks.pop_front(); 97 } 98 99 task(); 100 } 101 } 102 103 } 104