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