From c1bcd2e018923985a138c051d1b4b37fa1897995 Mon Sep 17 00:00:00 2001 From: FritzFlorian Date: Tue, 19 Mar 2019 11:05:02 +0100 Subject: [PATCH] First draft of thread class using c++11 standard. The first draft of the internal threading component is currently only implemented using the c++11 std::thread, pthread support will be added next. --- README.md | 5 ++++- lib/pls/CMakeLists.txt | 12 +++++++++++- lib/pls/include/pls/internal/base/thread.h | 131 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/pls/src/internal/base/thread.cpp | 1 + 4 files changed, 147 insertions(+), 2 deletions(-) create mode 100644 lib/pls/include/pls/internal/base/thread.h create mode 100644 lib/pls/src/internal/base/thread.cpp diff --git a/README.md b/README.md index 60b4e82..e4ed45a 100644 --- a/README.md +++ b/README.md @@ -36,4 +36,7 @@ As this project contains a lot concurrent code we use in our CI process and optional in other builds. To setup CMake builds with sanitizer enabled add the cmake option `-DTHREAD_SANITIZER=ON`. Please regularly test with thread sanitizer enabled and make sure to not -keep the repository in a state where the sanitizer reports errors. \ No newline at end of file +keep the repository in a state where the sanitizer reports errors. + +Consider reading [the section on common data races](https://github.com/google/sanitizers/wiki/ThreadSanitizerPopularDataRaces) +to get an idea of what we try to avoid in our code. \ No newline at end of file diff --git a/lib/pls/CMakeLists.txt b/lib/pls/CMakeLists.txt index 6feafc1..9226c17 100644 --- a/lib/pls/CMakeLists.txt +++ b/lib/pls/CMakeLists.txt @@ -1,6 +1,16 @@ # List all required files here (cmake best practice to NOT automate this step!) add_library(pls STATIC - src/library.cpp include/pls/library.h) + src/library.cpp include/pls/library.h + src/internal/base/thread.cpp include/pls/internal/base/thread.h) + +# Settings for our project... +# ...pthreads or C++ 11 threads +option(USING_PTHREADS "Build the tests" ON) +if(USING_PTHREADS) + target_compile_definitions(pls PUBLIC USING_PTHREADS) +else() + target_compile_definitions(pls PUBLIC USING_CPP_THREADS) +endif() # Add everything in `./include` to be in the include path of this project target_include_directories(pls diff --git a/lib/pls/include/pls/internal/base/thread.h b/lib/pls/include/pls/internal/base/thread.h new file mode 100644 index 0000000..b6202e9 --- /dev/null +++ b/lib/pls/include/pls/internal/base/thread.h @@ -0,0 +1,131 @@ +/** + * Abstraction for threading to allow porting. + * Currently using either pthread or C++ 11 threads. + */ + +#ifndef PLS_THREAD_H +#define PLS_THREAD_H + +// platform specific includes +#ifdef USING_PTHREADS + #include +#elif USING_CPP_THREADS + #include +#else + #error "Please configure exactly one threading library!" +#endif + +namespace pls { + namespace internal { + namespace base { + using thread_entrypoint = void(); + + // Thread local storage support +#ifdef USING_PTHREADS + pthread_key_t thr_id_key; + bool thr_id_key_created = false; + // forward declaration + int start_pthread_internal(void*); +#endif +#ifdef USING_CPP_THREADS + thread_local void* local_thread; +#endif + + + template + class thread { + private: + // Handle to the native thread used +#ifdef USING_PTHREADS + friend int start_pthread_internal(void*); + + pthread_t pthread_thread_; + thread_entrypoint entry_function_; + + thread(thread_entrypoint entry_function, T local_object): + pthread_thread_(), + entry_function_(entry_function), + local_object_(local_object) { + if (!thr_id_key_created) { + pthread_key_create(&thr_id_key, nullptr); + thr_id_key_created = true; + } + + pthread_create(&pthread_thread_, nullptr, start_pthread_internal, (void *)(this)); + } +#endif +#ifdef USING_CPP_THREADS + std::thread std_thread_; + + thread(thread_entrypoint entry_function, T local_object): + local_object_(local_object), + std_thread_([=](){ + local_thread = this; + entry_function(); + }) {}; +#endif + public: + T local_object_; + + /** + * Creates and starts a thread. + * NOT thread safe, best only use from one main thread managing the runtime! + * + * @param entry_function The entry function to run on the thread + * @param T local_object + * + * @return a handle to the newly created thread + */ + static thread start(thread_entrypoint entry_function, T local_object) { + return thread(entry_function, local_object); + } + + void join() { +#ifdef USING_PTHREADS + // TODO +#endif +#ifdef USING_CPP_THREADS + std_thread_.join(); +#endif + } + + static void yield() { +#ifdef USING_PTHREADS + // TODO +#endif +#ifdef USING_CPP_THREADS + std::this_thread::yield(); +#endif + } + + static thread* get_current() { +#ifdef USING_PTHREADS + // TODO +#endif +#ifdef USING_CPP_THREADS + return (thread*) local_thread; +#endif + } + + // make object move only + thread(thread&&) = default; + thread& operator=(thread&&) = default; + + thread(const thread&) = delete; + thread& operator=(const thread&) = delete; + }; + +#ifdef USING_PTHREADS + int start_pthread_internal(void* thread_pointer) { + thread* my_thread = (thread*)thread_pointer; + pthread_setspecific(thr_id_key, thread_pointer); + my_thread->entry_function_(); + pthread_exit(NULL); + } +#endif + } + } + +} + +#endif //PLS_THREAD_H diff --git a/lib/pls/src/internal/base/thread.cpp b/lib/pls/src/internal/base/thread.cpp new file mode 100644 index 0000000..2b1f521 --- /dev/null +++ b/lib/pls/src/internal/base/thread.cpp @@ -0,0 +1 @@ +#include "pls/internal/base/thread.h" -- libgit2 0.26.0