1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
|
// Copyright (C) 2003 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_THREADS_KERNEl_SHARED_
#define DLIB_THREADS_KERNEl_SHARED_
// this file should be included at the bottom of one of the thread kernel headers for a
// specific platform.
//#include "../threads.h"
#include "auto_mutex_extension.h"
#include "../binary_search_tree.h"
#include "../member_function_pointer.h"
#include "../memory_manager.h"
#include "../queue.h"
#include "../set.h"
#include "../test_for_odr_violations.h"
namespace dlib
{
// ----------------------------------------------------------------------------------------
namespace threads_kernel_shared
{
void thread_starter (
void*
);
class threader
{
/*!
INITIAL VALUE
- pool_count == 0 and
- data_ready is associated with the mutex data_mutex
- data_empty is associated with the mutex data_mutex
- destructed is associated with the mutex data_mutex
- destruct == false
- total_count == 0
- function_pointer == 0
- do_not_ever_destruct == false
CONVENTION
- data_ready is associated with the mutex data_mutex
- data_empty is associated with the mutex data_mutex
- data_ready == a signaler used signal when there is new data waiting
to start a thread with.
- data_empty == a signaler used to signal when the data is now empty
- pool_count == the number of suspended threads in the thread pool
- total_count == the number of threads that are executing anywhere. i.e.
pool_count + the ones that are currently running some user function.
- if (function_pointer != 0) then
- parameter == a void pointer pointing to the parameter which
should be used to start the next thread
- function_pointer == a pointer to the next function to make a
new thread with
- if (the destructor is running) then
- destruct == true
- else
- destruct == false
- thread_ids is locked by the data_mutex
- thread_ids == a set that contains the thread id for each thread spawned by this
object.
!*/
public:
threader (
);
~threader (
);
void destruct_if_ready (
);
/*!
ensures
- if (there are no threads currently running and we haven't set do_not_ever_destruct) then
- calls delete this
- else
- does nothing
!*/
bool create_new_thread (
void (*funct)(void*),
void* param
);
template <
typename T
>
void unregister_thread_end_handler (
T& obj,
void (T::*handler)()
)
{
member_function_pointer<> mfp, junk_mfp;
mfp.set(obj,handler);
thread_id_type junk_id;
// find any member function pointers in the registry that point to the same
// thing as mfp and remove them
auto_mutex M(reg.m);
reg.reg.reset();
while (reg.reg.move_next())
{
while (reg.reg.current_element_valid() && reg.reg.element().value() == mfp)
{
reg.reg.remove_current_element(junk_id, junk_mfp);
}
}
}
template <
typename T
>
void register_thread_end_handler (
T& obj,
void (T::*handler)()
)
{
thread_id_type id = get_thread_id();
member_function_pointer<> mfp;
mfp.set(obj,handler);
auto_mutex M(reg.m);
reg.reg.add(id,mfp);
}
bool is_dlib_thread (
thread_id_type id
);
private:
friend void thread_starter (
void*
);
void call_end_handlers (
);
/*!
ensures
- calls the registered end handlers for the calling thread and
then removes them from reg.reg
!*/
// private data
set<thread_id_type,memory_manager<char>::kernel_2b>::kernel_1b_c thread_ids;
unsigned long total_count;
void* parameter;
void (*function_pointer)(void*);
unsigned long pool_count;
mutex data_mutex; // mutex to protect the above data
signaler data_ready; // signaler to signal when there is new data
signaler data_empty; // signaler to signal when the data is empty
bool destruct;
signaler destructed; // signaler to signal when a thread has ended
bool do_not_ever_destruct;
struct registry_type
{
mutex m;
binary_search_tree<
thread_id_type,
member_function_pointer<>,
memory_manager<char>::kernel_2a
>::kernel_2a_c reg;
};
// stuff for the register_thread_end_handler
registry_type reg;
// restricted functions
threader(threader&); // copy constructor
threader& operator=(threader&); // assignement opertor
};
// ------------------------------------------------------------------------------------
threader& thread_pool (
);
/*!
ensures
- returns a reference to the global threader object
!*/
// ------------------------------------------------------------------------------------
extern bool thread_pool_has_been_destroyed;
}
bool is_dlib_thread (
thread_id_type id
);
bool is_dlib_thread (
);
// ----------------------------------------------------------------------------------------
inline bool create_new_thread (
void (*funct)(void*),
void* param
)
{
try
{
// now make this thread
return threads_kernel_shared::thread_pool().create_new_thread(funct,param);
}
catch (std::bad_alloc&)
{
return false;
}
}
// ----------------------------------------------------------------------------------------
template <
typename T
>
inline void register_thread_end_handler (
T& obj,
void (T::*handler)()
)
{
DLIB_ASSERT(is_dlib_thread(),
"\tvoid register_thread_end_handler"
<< "\n\tYou can't register a thread end handler for a thread dlib didn't spawn."
);
threads_kernel_shared::thread_pool().register_thread_end_handler(obj,handler);
}
// ----------------------------------------------------------------------------------------
template <
typename T
>
inline void unregister_thread_end_handler (
T& obj,
void (T::*handler)()
)
{
// Check if the thread pool has been destroyed and if it has then don't do anything.
// This bool here is always true except when the program has started to terminate and
// the thread pool object has been destroyed. This if is here to catch other global
// objects that have destructors that try to call unregister_thread_end_handler().
// Without this check we get into trouble if the thread pool is destroyed before these
// objects.
if (threads_kernel_shared::thread_pool_has_been_destroyed == false)
threads_kernel_shared::thread_pool().unregister_thread_end_handler(obj,handler);
}
// ----------------------------------------------------------------------------------------
}
#ifdef NO_MAKEFILE
#include "threads_kernel_shared.cpp"
#endif
#endif // DLIB_THREADS_KERNEl_SHARED_
|