From 7dfa2a34c26437c048b78f1962dc9b9cf84eb355 Mon Sep 17 00:00:00 2001 From: FritzFlorian Date: Wed, 20 Mar 2019 11:14:32 +0100 Subject: [PATCH] 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. --- app/test_for_new/main.cpp | 3 +-- lib/pls/include/pls/internal/base/thread.h | 40 ++++++++++++++++++++++++++++------------ test/thread_tests.cpp | 12 ++++++------ 3 files changed, 35 insertions(+), 20 deletions(-) diff --git a/app/test_for_new/main.cpp b/app/test_for_new/main.cpp index 245c292..d04050f 100644 --- a/app/test_for_new/main.cpp +++ b/app/test_for_new/main.cpp @@ -8,7 +8,6 @@ int global = 0; int main() { // Try to use every feature, to trigger the prohibited use of new if found somewhere - auto t1 = create_thread([] (){}, 0); - t1.start(); + auto t1 = start_thread([] (){}); t1.join(); } diff --git a/lib/pls/include/pls/internal/base/thread.h b/lib/pls/include/pls/internal/base/thread.h index c4ed39b..265190e 100644 --- a/lib/pls/include/pls/internal/base/thread.h +++ b/lib/pls/include/pls/internal/base/thread.h @@ -25,14 +25,28 @@ namespace pls { 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 static T* state() { return reinterpret_cast(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 - static void set_state(const T& state) { - *reinterpret_cast(pthread_getspecific(local_storage_key_)) = state; + static void set_state(T* state_pointer) { + pthread_setspecific(this_thread::local_storage_key_, (void*)state_pointer); } }; @@ -41,26 +55,24 @@ namespace pls { friend class this_thread; // Keep a copy of the function (lambda) in this object to make sure it is valid when called! Function function_; - // Keep the local state we hold in here - State state_; + State* state_pointer_; // Keep handle to native implementation pthread_t pthread_thread_; static void* start_pthread_internal(void* thread_pointer) { auto my_thread = reinterpret_cast(thread_pointer); - pthread_setspecific(this_thread::local_storage_key_, (void*)&my_thread->state_); + this_thread::set_state(my_thread->state_pointer_); my_thread->function_(); pthread_exit(nullptr); } public: - explicit thread(const Function& function, const State& state): - function_{function}, - state_{state}, - pthread_thread_{} {} + explicit thread(const Function& function, State* state_pointer): + function_{function}, + state_pointer_{state_pointer}, + pthread_thread_{} { - void start() { if (!this_thread::local_storage_key_initialized_) { pthread_key_create(&this_thread::local_storage_key_, nullptr); this_thread::local_storage_key_initialized_ = true; @@ -82,10 +94,14 @@ namespace pls { }; template - thread create_thread(const Function& function, const State& state) { - return thread(function, state); + thread start_thread(const Function& function, State* state_pointer) { + return thread(function, state_pointer); } + template + thread start_thread(const Function& function) { + return thread(function, nullptr); + } } } diff --git a/test/thread_tests.cpp b/test/thread_tests.cpp index 4ac6740..03809fe 100644 --- a/test/thread_tests.cpp +++ b/test/thread_tests.cpp @@ -12,18 +12,18 @@ static vector local_value_two; TEST_CASE( "thread creation and joining", "[internal/base/thread.h]") { visited = false; - auto t1 = create_thread([]() { visited = true; }, 0); - t1.start(); + auto t1 = start_thread([]() { visited = true; }); t1.join(); REQUIRE(visited); } TEST_CASE( "thread state", "[internal/base/thread.h]") { - auto t1 = create_thread([]() { local_value_1 = *this_thread::state(); }, 1); - auto t2 = create_thread([]() { local_value_two = *this_thread::state>(); }, vector{1, 2}); - t1.start(); - t2.start(); + int state_one = 1; + vector state_two{1, 2}; + + auto t1 = start_thread([]() { local_value_1 = *this_thread::state(); }, &state_one); + auto t2 = start_thread([]() { local_value_two = *this_thread::state>(); }, &state_two); t1.join(); t2.join(); -- libgit2 0.26.0