You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
concurrentqueue/benchmarks/dlib/threads/threads_kernel_shared.h

275 lines
8.6 KiB
C++

// 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_