# HG changeset patch # User Olaf Wintermann # Date 1706471209 -3600 # Node ID 9c79f00fbf361e7641096b797b8bf92659ce15a4 # Parent 9036b346cd661864f35b66925a65f894c35e358e add threadpool (WinUI3) diff -r 9036b346cd66 -r 9c79f00fbf36 make/vs/testapp/main.c --- a/make/vs/testapp/main.c Sun Jan 28 19:33:56 2024 +0100 +++ b/make/vs/testapp/main.c Sun Jan 28 20:46:49 2024 +0100 @@ -185,6 +185,7 @@ } + void application_startup(UiEvent* event, void* data) { UiContext* gctx = ui_global_context(); menuList = ui_list_new(gctx, "menulist"); diff -r 9036b346cd66 -r 9c79f00fbf36 ui/ui/toolkit.h --- a/ui/ui/toolkit.h Sun Jan 28 19:33:56 2024 +0100 +++ b/ui/ui/toolkit.h Sun Jan 28 20:46:49 2024 +0100 @@ -163,6 +163,8 @@ typedef struct UiImage UiImage; typedef struct UiDnD UiDnD; + +typedef struct UiThreadpool UiThreadpool; /* end opaque types */ typedef struct UiTabbedPane UiTabbedPane; @@ -372,6 +374,9 @@ UIEXPORT void ui_job(UiObject *obj, ui_threadfunc tf, void *td, ui_callback f, void *fd); UIEXPORT void ui_call_mainthread(ui_threadfunc tf, void* td); +UIEXPORT UiThreadpool* ui_threadpool_create(int nthreads); +UIEXPORT void ui_threadpool_destroy(UiThreadpool* pool); +UIEXPORT void ui_threadpool_job(UiThreadpool* pool, UiObject* obj, ui_threadfunc tf, void* td, ui_callback f, void* fd); UIEXPORT void* ui_document_new(size_t size); UIEXPORT void ui_document_destroy(void *doc); diff -r 9036b346cd66 -r 9c79f00fbf36 ui/winui/toolkit.cpp --- a/ui/winui/toolkit.cpp Sun Jan 28 19:33:56 2024 +0100 +++ b/ui/winui/toolkit.cpp Sun Jan 28 20:46:49 2024 +0100 @@ -43,8 +43,6 @@ #include "App.xaml.h" -#include - using namespace winrt; using namespace Microsoft::UI::Xaml; using namespace Microsoft::UI::Xaml::Controls; @@ -251,7 +249,7 @@ } static void ui_job_thread(UiJob* job) { - if (!job->job_func(job->job_data)) { + if (!job->job_func(job->job_data) && job->finish_callback) { bool isQueued = uiDispatcherQueue.TryEnqueue([job]() { UiEvent event; @@ -295,3 +293,70 @@ exit(-1); } } + +static UiJob kill_job; // &kill_job indicates to stop the thread + +static void ui_threadpool_run(UiThreadpool* pool) { + for (;;) { + UiJob* job = pool->GetJob(); + if (job == &kill_job) { + return; + } + else if (job) { + ui_job_thread(job); + } + } +} + +UiThreadpool::UiThreadpool(int nthreads) { + for (int i = 0; i < nthreads; i++) { + std::thread thread(ui_threadpool_run, this); + thread.detach(); + } +} + +void UiThreadpool::EnqueueJob(UiJob* job) +{ + std::unique_lock lock(mutex); + queue.push(job); + lock.unlock(); + condition.notify_one(); +} + +UiJob* UiThreadpool::GetJob() { + std::unique_lock lock(mutex); + + UiJob* job = nullptr; + while (!job) { + if (queue.empty()) { + condition.wait(lock); + continue; + } + else + { + job = queue.front(); + queue.pop(); + } + } + + return job; +} + +UIEXPORT UiThreadpool* ui_threadpool_create(int nthreads) { + return new UiThreadpool(nthreads); +} + +UIEXPORT void ui_threadpool_destroy(UiThreadpool* pool) { + // TODO +} + +UIEXPORT void ui_threadpool_job(UiThreadpool* pool, UiObject* obj, ui_threadfunc tf, void* td, ui_callback f, void* fd) { + UiJob* job = new UiJob; + job->obj = obj; + job->job_func = tf; + job->job_data = td; + job->finish_callback = f; + job->finish_data = fd; + pool->EnqueueJob(job); +} + diff -r 9036b346cd66 -r 9c79f00fbf36 ui/winui/toolkit.h --- a/ui/winui/toolkit.h Sun Jan 28 19:33:56 2024 +0100 +++ b/ui/winui/toolkit.h Sun Jan 28 20:46:49 2024 +0100 @@ -30,6 +30,10 @@ #include "../ui/toolkit.h" +#include +#include +#include + typedef struct UiJob { UiObject* obj; ui_threadfunc job_func; @@ -38,6 +42,19 @@ void* finish_data; } UiJob; +struct UiThreadpool +{ + std::queue queue; + std::mutex mutex; + std::condition_variable condition; + + UiThreadpool(int nthreads); + + void EnqueueJob(UiJob* job); + + UiJob* GetJob(); +}; + typedef void(*ui_eventfunc)(void*, void*); void ui_app_run_startup();