Feature Selection Toolbox FST4
UTIA · Czech Academy of Sciences
Loading...
Searching...
No Matches
thread_pool.hpp
Go to the documentation of this file.
1#ifndef FSTTHREADPOOL_H
2#define FSTTHREADPOOL_H
3 /*
27=========================================================================
28Copyright and license:
29 * FST4 software (with the exception of any bundled or externally linked
30 third-party components) is Copyright (C) 2000-present Institute of
31 Information Theory and Automation of the Czech Academy of Sciences (UTIA).
32 * FST4 is free software: you can redistribute it and/or modify it under
33 the terms of the GNU Affero General Public License as published by the
34 Free Software Foundation, version 3. The full text of the license is in
35 the file LICENSE in the distribution root and at
36 https://www.gnu.org/licenses/agpl-3.0.html.
37 * FST4 is distributed in the hope that it will be useful, but WITHOUT ANY
38 WARRANTY; without even the implied warranty of MERCHANTABILITY or
39 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
40 License for more details.
41 * Closed-source use without the AGPL's copyleft obligations requires a
42 commercial license from UTIA; in case of interest write to
43 utia@utia.cas.cz. LICENSING.md in the distribution root explains both
44 options, the contributor license agreement that every contribution
45 requires, and the contacts (technical questions and pull requests:
46 somol@utia.cas.cz, with "FST" in the subject line).
47========================================================================== */
48
49#include <atomic>
50#include <thread>
51#include <mutex>
52#include <condition_variable>
53#include <functional>
54#include <iostream>
55#include <memory>
56#include <vector>
57#include <cassert>
58#include "global.hpp"
59
60namespace FST {
61
73{
74public:
77 explicit ThreadPool(const unsigned int max_threads=2) : _max_threads(max_threads), threads(max_threads), _running_threads(0)
78 {
79 assert(max_threads>0);
80 for(unsigned int i=0;i<_max_threads;i++) threads[i].tid=-1;
81 }
82
83 ~ThreadPool() {notify("ThreadPool destructor, idx=",tid_counter().load()); join_all();}
84
85 unsigned int get_max_threads() const {return _max_threads;}
86
94 unsigned int go(const std::function<void()> &threadfunc)
95 {
96 std::unique_lock<std::mutex> lock_launcher(mutex_launcher);
98 {
99 notify("Max allowed threads running, waiting for one to end...");
100 while (_running_threads==_max_threads) cond_launcher.wait(lock_launcher);
101 }
102 unsigned int free_tidx=0;
103 while(free_tidx<_max_threads && threads[free_tidx].tid!=-1) free_tidx++;
104 assert(free_tidx<_max_threads);
105 {
106 notify("Launching thread, tid=",tid_counter().load(),"...");
107 {
109 }
110 if(threads[free_tidx].m_thread)
111 {
112 notify("Joining past ",free_tidx,"th thread before lanching new one.");
113 threads[free_tidx].m_thread->join();
114 }
115 {
116 threads[free_tidx].tid=tid_counter()++;
117 threads[free_tidx].m_thread.reset(new std::thread(std::bind(&ThreadPool::launch_thread,this,threadfunc,free_tidx)));
118 notify("Thread tid=",threads[free_tidx].tid," (",free_tidx,"th) launched...");
119 }
120 }
121 return free_tidx;
122 }
123
126 void join_all()
127 {
128 notify("Calling join_all...");
129 for(unsigned int i=0; i<_max_threads; i++)
130 {
131 // take ownership of the thread handle under the lock, but join outside it -
132 // the finishing worker needs mutex_launcher in launch_thread()
133 ThreadPtr t;
134 {
135 std::unique_lock<std::mutex> lock(mutex_launcher);
136 assert((threads[i].m_thread && threads[i].tid>=0) || (threads[i].tid==-1));
137 t.swap(threads[i].m_thread);
138 }
139 if(t)
140 {
141 notify("join_all: Joining ",i,"th thread.");
142 t->join();
143 std::unique_lock<std::mutex> lock(mutex_launcher);
144 threads[i].tid=-1;
145 }
146 }
147 {
148 std::unique_lock<std::mutex> lock(mutex_launcher);
150 }
151 notify("join_all finished...");
152 }
153
157 unsigned int get_running_threads() const {return _running_threads;}
158
159private:
160 // the next procedure must be re-entrant
164 void launch_thread(const std::function<void()> &threadfunc, unsigned int threadsid)
165 {
166 notify("Starting launch_thread(tid=",threads[threadsid].tid,", ",threadsid,"th) ...");
167 threadfunc();
168 notify("Finishing launch_thread(tid=",threads[threadsid].tid,", ",threadsid,"th).");
169 {
170 std::unique_lock<std::mutex> lock(mutex_launcher);
172 threads[threadsid].tid=-1;
173 }
174 {
175 cond_launcher.notify_one();
176 }
177 }
178private:
179 typedef std::unique_ptr<std::thread> ThreadPtr;
181 typedef struct {
183 int tid;
184 } ThreadsArray;
185 const unsigned int _max_threads;
186 std::vector<ThreadsArray> threads;
187
188private:
190 static std::atomic<unsigned int>& tid_counter() {static std::atomic<unsigned int> c(0); return c;}
191 unsigned int _running_threads;
192
193 std::mutex mutex_launcher;
194 std::condition_variable cond_launcher;
195};
196
197} // namespace
198#endif // FSTTHREADPOOL_H ///:~
~ThreadPool()
Joins every in-flight job before destroying the pool.
Definition thread_pool.hpp:83
unsigned int get_max_threads() const
returns the pool capacity (max_threads as given to the constructor)
Definition thread_pool.hpp:85
ThreadPool(const unsigned int max_threads=2)
Constructs a pool that allows up to max_threads concurrently running worker threads.
Definition thread_pool.hpp:77
unsigned int go(const std::function< void()> &threadfunc)
Launches threadfunc in a free pool slot, blocking the caller until one becomes available if the pool ...
Definition thread_pool.hpp:94
const unsigned int _max_threads
pool capacity, fixed at construction
Definition thread_pool.hpp:185
std::condition_variable cond_launcher
signaled by launch_thread() when a slot frees up, to wake a go() call waiting for capacity
Definition thread_pool.hpp:194
static std::atomic< unsigned int > & tid_counter()
process-wide tid sequence for notify() diagnostics (function-local static avoids header ODR issues)
Definition thread_pool.hpp:190
std::unique_ptr< std::thread > ThreadPtr
Definition thread_pool.hpp:179
std::vector< ThreadsArray > threads
one slot per allowed concurrent thread; sized once in the constructor, never resized (no reallocation...
Definition thread_pool.hpp:186
std::mutex mutex_launcher
guards threads[], _running_threads and slot bookkeeping in go()/join_all()/launch_thread()
Definition thread_pool.hpp:193
unsigned int get_running_threads() const
Returns the number of pool slots with an active thread right now. The counter is read without taking ...
Definition thread_pool.hpp:157
void launch_thread(const std::function< void()> &threadfunc, unsigned int threadsid)
Worker-thread trampoline: runs threadfunc to completion, then marks slot threadsid free and wakes one...
Definition thread_pool.hpp:164
void join_all()
Joins every currently running worker thread and resets the pool to empty (all slots free)....
Definition thread_pool.hpp:126
unsigned int _running_threads
current count of slots with an active thread (guarded by mutex_launcher)
Definition thread_pool.hpp:191
Global definitions.
The Feature Selection Toolbox 4 library: every library component – data access, criteria and classifi...
Definition data_accessor.hpp:80
void notify(const std::string msg)
Prints msg followed by a newline via syncout::print(); a no-op unless the preprocessor macro DEBUG is...
Definition global.hpp:112
Structure to keep status of threads in the pool.
Definition thread_pool.hpp:181
int tid
monotonically increasing id assigned when a thread is launched into this slot, -1 if the slot is free
Definition thread_pool.hpp:183
ThreadPtr m_thread
owns the worker thread's std::thread handle, or null if this slot is free
Definition thread_pool.hpp:182
Copyright © 2000–present ÚTIA, Institute of Information Theory and Automation of the Czech Academy of Sciences · Contacts · This site sets no cookies and uses no analytics.