Modernize Thread

- Based on C++11's `thread` and `thread_local`
- No more need to allocate-deallocate or check for null
- No pointer anymore, just a member variable
- Platform-specific implementations no longer needed (except for the few cases of non-portable functions)
- Simpler for `NO_THREADS`
- Thread ids are now the same across platforms (main is 1; others follow)
This commit is contained in:
Pedro J. Estébanez
2021-01-19 13:29:41 +01:00
parent 6ddfc8e718
commit 99fe462452
87 changed files with 385 additions and 1056 deletions

View File

@@ -30,30 +30,70 @@
#include "thread.h"
Thread *(*Thread::create_func)(ThreadCreateCallback, void *, const Settings &) = nullptr;
Thread::ID (*Thread::get_thread_id_func)() = nullptr;
void (*Thread::wait_to_finish_func)(Thread *) = nullptr;
#include "core/object/script_language.h"
#if !defined(NO_THREADS)
Error (*Thread::set_name_func)(const String &) = nullptr;
void (*Thread::set_priority_func)(Thread::Priority) = nullptr;
void (*Thread::init_func)() = nullptr;
void (*Thread::term_func)() = nullptr;
Thread::ID Thread::_main_thread_id = 0;
Thread::ID Thread::main_thread_id = 1;
Thread::ID Thread::last_thread_id = 1;
thread_local Thread::ID Thread::caller_id = 1;
Thread::ID Thread::get_caller_id() {
if (get_thread_id_func) {
return get_thread_id_func();
}
return 0;
void Thread::_set_platform_funcs(
Error (*p_set_name_func)(const String &),
void (*p_set_priority_func)(Thread::Priority),
void (*p_init_func)(),
void (*p_term_func)()) {
Thread::set_name_func = p_set_name_func;
Thread::set_priority_func = p_set_priority_func;
Thread::init_func = p_init_func;
Thread::term_func = p_term_func;
}
Thread *Thread::create(ThreadCreateCallback p_callback, void *p_user, const Settings &p_settings) {
if (create_func) {
return create_func(p_callback, p_user, p_settings);
void Thread::callback(Thread *p_self, const Settings &p_settings, Callback p_callback, void *p_userdata) {
Thread::caller_id = p_self->id;
if (set_priority_func) {
set_priority_func(p_settings.priority);
}
if (init_func) {
init_func();
}
ScriptServer::thread_enter(); //scripts may need to attach a stack
p_callback(p_userdata);
ScriptServer::thread_exit();
if (term_func) {
term_func();
}
return nullptr;
}
void Thread::wait_to_finish(Thread *p_thread) {
if (wait_to_finish_func) {
wait_to_finish_func(p_thread);
void Thread::start(Thread::Callback p_callback, void *p_user, const Settings &p_settings) {
if (id != 0) {
#ifdef DEBUG_ENABLED
WARN_PRINT("A Thread object has been re-started without wait_to_finish() having been called on it. Please do so to ensure correct cleanup of the thread.");
#endif
thread.detach();
std::thread empty_thread;
thread.swap(empty_thread);
}
id = atomic_increment(&last_thread_id);
std::thread new_thread(&Thread::callback, this, p_settings, p_callback, p_user);
thread.swap(new_thread);
}
bool Thread::is_started() const {
return id != 0;
}
void Thread::wait_to_finish() {
if (id != 0) {
thread.join();
std::thread empty_thread;
thread.swap(empty_thread);
id = 0;
}
}
@@ -64,3 +104,14 @@ Error Thread::set_name(const String &p_name) {
return ERR_UNAVAILABLE;
}
Thread::~Thread() {
if (id != 0) {
#ifdef DEBUG_ENABLED
WARN_PRINT("A Thread object has been destroyed without wait_to_finish() having been called on it. Please do so to ensure correct cleanup of the thread.");
#endif
thread.detach();
}
}
#endif