diff --git a/CMakePresets.json b/CMakePresets.json index 8f412dd..b84fafb 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -17,7 +17,8 @@ "inherits": "default", "cacheVariables": { "FISHBONE_BUILD_TESTS": "ON", - "CMAKE_EXPORT_COMPILE_COMMANDS": "ON" + "CMAKE_EXPORT_COMPILE_COMMANDS": "ON", + "CMAKE_BUILD_TYPE": "Debug" } } ], diff --git a/engine/include/fishbone/machdep.h b/engine/include/fishbone/machdep.h index 8e7b4ac..e6588ef 100644 --- a/engine/include/fishbone/machdep.h +++ b/engine/include/fishbone/machdep.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include diff --git a/engine/include/fishbone/thread.h b/engine/include/fishbone/thread.h index 014bd9b..1833780 100644 --- a/engine/include/fishbone/thread.h +++ b/engine/include/fishbone/thread.h @@ -14,7 +14,11 @@ namespace fishbone { Impl* impl; public: - Thread(void (*call)(fishbone::Thread* thread, void* arg), void* arg); + using Callable = void(*)(fishbone::Thread* thread, void* arg); + using CallableFunc = std::function; + + Thread(Callable call, void* arg); + Thread(CallableFunc call); ~Thread(); void join(); diff --git a/engine/src/thread/sdl2.cc b/engine/src/thread/sdl2.cc index 7f99e6f..7b0ffa4 100644 --- a/engine/src/thread/sdl2.cc +++ b/engine/src/thread/sdl2.cc @@ -3,9 +3,14 @@ #include struct call_arg { - void (*call)(fishbone::Thread* thread, void* arg); - fishbone::Thread* thread; - void* arg; + fishbone::Thread::Callable call; + fishbone::Thread* thread; + void* arg; +}; + +struct call_arg2 { + fishbone::Thread::CallableFunc call; + fishbone::Thread* thread; }; static int SDLCALL thread_call(void* data) { @@ -18,11 +23,21 @@ static int SDLCALL thread_call(void* data) { return 0; } +static int SDLCALL thread_call2(void* data) { + struct call_arg2* arg = (struct call_arg2*)data; + + arg->call(arg->thread); + + delete arg; + + return 0; +} + struct fishbone::Thread::Impl { SDL_Thread* thread; }; -fishbone::Thread::Thread(void (*call)(fishbone::Thread* thread, void* arg), void* arg) { +fishbone::Thread::Thread(Callable call, void* arg) { struct call_arg* data = new struct call_arg(); data->call = call; @@ -33,6 +48,16 @@ fishbone::Thread::Thread(void (*call)(fishbone::Thread* thread, void* arg), void this->impl->thread = SDL_CreateThread(thread_call, "FBThread", data); } +fishbone::Thread::Thread(CallableFunc call) { + struct call_arg2* data = new struct call_arg2(); + + data->call = call; + data->thread = this; + + this->impl = new fishbone::Thread::Impl(); + this->impl->thread = SDL_CreateThread(thread_call2, "FBThread", data); +} + fishbone::Thread::~Thread() { this->join(); } diff --git a/engine/tests/src/placeholder.cc b/engine/tests/src/placeholder.cc deleted file mode 100644 index 96821ce..0000000 --- a/engine/tests/src/placeholder.cc +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/engine/tests/src/thread.cc b/engine/tests/src/thread.cc new file mode 100644 index 0000000..f2f8811 --- /dev/null +++ b/engine/tests/src/thread.cc @@ -0,0 +1,59 @@ +#include "fishbone/thread.h" +#include +#include +#include +#include + +struct thread_arg { + int& a; +}; + +TEST_CASE("Thread") { + int a = 0; + + fishbone::Thread th([&a](auto) { + for (int i = 0; i < 100; i++) { + a++; + } + }); + + th.join(); + REQUIRE(a == 100); + + a = 0; + + thread_arg arg { a }; + fishbone::Thread th2([](auto, void* data) { + thread_arg& arg = *static_cast(data); + + for (int i = 0; i < 100; i++) { + arg.a++; + } + }, &arg); + + th.join(); + REQUIRE(a == 100); +} + +TEST_CASE("Mutex") { + for (int i = 0; i < 100; i++) { + int a = 0; + fishbone::Mutex m; + + fishbone::Thread::CallableFunc func = [&a, &m](auto) { + m.lock(); + for (int j = 0; j < 2; j++) { + int b = a; + usleep((60 * rand()) / RAND_MAX); + a = ++b; + } + m.unlock(); + }; + + fishbone::Thread th1(func), th2(func); + + th1.join(); + th2.join(); + REQUIRE(a == 4); + } +} \ No newline at end of file