Commit 7dfa2a34 by FritzFlorian

Move thread local state OUT of thread object.

This requires the user to explicitly manage the storage duration/place of the thread local state, making a fine grained memory allocation simpler.
parent 73ed4960
Pipeline #1098 passed with stages
in 1 minute 35 seconds
...@@ -8,7 +8,6 @@ int global = 0; ...@@ -8,7 +8,6 @@ int global = 0;
int main() { int main() {
// Try to use every feature, to trigger the prohibited use of new if found somewhere // Try to use every feature, to trigger the prohibited use of new if found somewhere
auto t1 = create_thread([] (){}, 0); auto t1 = start_thread([] (){});
t1.start();
t1.join(); t1.join();
} }
...@@ -25,14 +25,28 @@ namespace pls { ...@@ -25,14 +25,28 @@ namespace pls {
pthread_yield(); pthread_yield();
} }
/**
* Retrieves the local state pointer.
*
* @tparam T The type of the state that is stored.
* @return The state pointer hold for this thread.
*/
template<typename T> template<typename T>
static T* state() { static T* state() {
return reinterpret_cast<T*>(pthread_getspecific(local_storage_key_)); return reinterpret_cast<T*>(pthread_getspecific(local_storage_key_));
} }
/**
* Stores a pointer to the thread local state object.
* The memory management for this has to be done by the user,
* we only keep the pointer.
*
* @tparam T The type of the state that is stored.
* @param state_pointer A pointer to the threads state object.
*/
template<typename T> template<typename T>
static void set_state(const T& state) { static void set_state(T* state_pointer) {
*reinterpret_cast<T*>(pthread_getspecific(local_storage_key_)) = state; pthread_setspecific(this_thread::local_storage_key_, (void*)state_pointer);
} }
}; };
...@@ -41,26 +55,24 @@ namespace pls { ...@@ -41,26 +55,24 @@ namespace pls {
friend class this_thread; friend class this_thread;
// Keep a copy of the function (lambda) in this object to make sure it is valid when called! // Keep a copy of the function (lambda) in this object to make sure it is valid when called!
Function function_; Function function_;
// Keep the local state we hold in here State* state_pointer_;
State state_;
// Keep handle to native implementation // Keep handle to native implementation
pthread_t pthread_thread_; pthread_t pthread_thread_;
static void* start_pthread_internal(void* thread_pointer) { static void* start_pthread_internal(void* thread_pointer) {
auto my_thread = reinterpret_cast<thread*>(thread_pointer); auto my_thread = reinterpret_cast<thread*>(thread_pointer);
pthread_setspecific(this_thread::local_storage_key_, (void*)&my_thread->state_); this_thread::set_state(my_thread->state_pointer_);
my_thread->function_(); my_thread->function_();
pthread_exit(nullptr); pthread_exit(nullptr);
} }
public: public:
explicit thread(const Function& function, const State& state): explicit thread(const Function& function, State* state_pointer):
function_{function}, function_{function},
state_{state}, state_pointer_{state_pointer},
pthread_thread_{} {} pthread_thread_{} {
void start() {
if (!this_thread::local_storage_key_initialized_) { if (!this_thread::local_storage_key_initialized_) {
pthread_key_create(&this_thread::local_storage_key_, nullptr); pthread_key_create(&this_thread::local_storage_key_, nullptr);
this_thread::local_storage_key_initialized_ = true; this_thread::local_storage_key_initialized_ = true;
...@@ -82,10 +94,14 @@ namespace pls { ...@@ -82,10 +94,14 @@ namespace pls {
}; };
template<typename Function, typename State> template<typename Function, typename State>
thread<Function, State> create_thread(const Function& function, const State& state) { thread<Function, State> start_thread(const Function& function, State* state_pointer) {
return thread<Function, State>(function, state); return thread<Function, State>(function, state_pointer);
} }
template<typename Function>
thread<Function, void> start_thread(const Function& function) {
return thread<Function, void>(function, nullptr);
}
} }
} }
......
...@@ -12,18 +12,18 @@ static vector<int> local_value_two; ...@@ -12,18 +12,18 @@ static vector<int> local_value_two;
TEST_CASE( "thread creation and joining", "[internal/base/thread.h]") { TEST_CASE( "thread creation and joining", "[internal/base/thread.h]") {
visited = false; visited = false;
auto t1 = create_thread([]() { visited = true; }, 0); auto t1 = start_thread([]() { visited = true; });
t1.start();
t1.join(); t1.join();
REQUIRE(visited); REQUIRE(visited);
} }
TEST_CASE( "thread state", "[internal/base/thread.h]") { TEST_CASE( "thread state", "[internal/base/thread.h]") {
auto t1 = create_thread([]() { local_value_1 = *this_thread::state<int>(); }, 1); int state_one = 1;
auto t2 = create_thread([]() { local_value_two = *this_thread::state<vector<int>>(); }, vector<int>{1, 2}); vector<int> state_two{1, 2};
t1.start();
t2.start(); auto t1 = start_thread([]() { local_value_1 = *this_thread::state<int>(); }, &state_one);
auto t2 = start_thread([]() { local_value_two = *this_thread::state<vector<int>>(); }, &state_two);
t1.join(); t1.join();
t2.join(); t2.join();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment