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.
142 lines
4.0 KiB
C++
142 lines
4.0 KiB
C++
// Copyright (C) 2006 Davis E. King (davis@dlib.net)
|
|
// License: Boost Software License See LICENSE.txt for the full license.
|
|
#ifndef DLIB_THREAD_SPECIFIC_DATA_EXTENSIOn_
|
|
#define DLIB_THREAD_SPECIFIC_DATA_EXTENSIOn_
|
|
|
|
#include "thread_specific_data_extension_abstract.h"
|
|
#include "threads_kernel_abstract.h"
|
|
#include "../binary_search_tree.h"
|
|
#include "auto_mutex_extension.h"
|
|
|
|
namespace dlib
|
|
{
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename T
|
|
>
|
|
class thread_specific_data
|
|
{
|
|
/*!
|
|
CONVENTION
|
|
- for all valid ID:
|
|
(*items[ID]) == pointer to the data for thread with id ID
|
|
!*/
|
|
public:
|
|
|
|
thread_specific_data (
|
|
)
|
|
{
|
|
thread_end_handler_calls_left = 0;
|
|
}
|
|
|
|
~thread_specific_data (
|
|
)
|
|
{
|
|
// We should only call the unregister_thread_end_handler function if there are
|
|
// some outstanding callbacks we expect to get. Otherwise lets avoid calling it
|
|
// since the dlib state that maintains the registered thread end handlers may have
|
|
// been destructed already (since the program might be in the process of terminating).
|
|
bool call_unregister = false;
|
|
m.lock();
|
|
if (thread_end_handler_calls_left > 0)
|
|
call_unregister = true;
|
|
m.unlock();
|
|
|
|
if (call_unregister)
|
|
unregister_thread_end_handler(const_cast<thread_specific_data&>(*this),&thread_specific_data::thread_end_handler);
|
|
|
|
auto_mutex M(m);
|
|
items.reset();
|
|
while (items.move_next())
|
|
{
|
|
delete items.element().value();
|
|
}
|
|
}
|
|
|
|
inline T& data (
|
|
) { return get_data(); }
|
|
|
|
inline const T& data (
|
|
) const { return get_data(); }
|
|
|
|
private:
|
|
|
|
T& get_data (
|
|
) const
|
|
{
|
|
thread_id_type id = get_thread_id();
|
|
auto_mutex M(m);
|
|
|
|
T** item = items[id];
|
|
if (item)
|
|
{
|
|
return **item;
|
|
}
|
|
else
|
|
{
|
|
// register an end handler for this thread so long as it is a dlib created thread.
|
|
T* new_item = new T;
|
|
|
|
bool in_tree = false;
|
|
try
|
|
{
|
|
T* temp_item = new_item;
|
|
thread_id_type temp_id = id;
|
|
items.add(temp_id,temp_item);
|
|
in_tree = true;
|
|
|
|
if (is_dlib_thread(id))
|
|
{
|
|
register_thread_end_handler(const_cast<thread_specific_data&>(*this),&thread_specific_data::thread_end_handler);
|
|
++thread_end_handler_calls_left;
|
|
}
|
|
}
|
|
catch (...)
|
|
{
|
|
if (in_tree)
|
|
{
|
|
items.destroy(id);
|
|
}
|
|
delete new_item;
|
|
throw;
|
|
}
|
|
|
|
return *new_item;
|
|
}
|
|
}
|
|
|
|
void thread_end_handler (
|
|
)
|
|
{
|
|
const thread_id_type id = get_thread_id();
|
|
thread_id_type junk = 0;
|
|
T* item = 0;
|
|
auto_mutex M(m);
|
|
--thread_end_handler_calls_left;
|
|
if (items[id])
|
|
{
|
|
items.remove(id,junk,item);
|
|
delete item;
|
|
}
|
|
}
|
|
|
|
mutable typename binary_search_tree<thread_id_type,T*>::kernel_2a items;
|
|
mutex m;
|
|
mutable long thread_end_handler_calls_left;
|
|
|
|
// restricted functions
|
|
thread_specific_data(thread_specific_data&); // copy constructor
|
|
thread_specific_data& operator=(thread_specific_data&); // assignment operator
|
|
};
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
}
|
|
|
|
#endif // DLIB_THREAD_SPECIFIC_DATA_EXTENSIOn_
|
|
|
|
|
|
|