aboutsummaryrefslogtreecommitdiff
path: root/Src/nu/threadpool/ThreadPool.h
diff options
context:
space:
mode:
Diffstat (limited to 'Src/nu/threadpool/ThreadPool.h')
-rw-r--r--Src/nu/threadpool/ThreadPool.h98
1 files changed, 98 insertions, 0 deletions
diff --git a/Src/nu/threadpool/ThreadPool.h b/Src/nu/threadpool/ThreadPool.h
new file mode 100644
index 00000000..f68efc12
--- /dev/null
+++ b/Src/nu/threadpool/ThreadPool.h
@@ -0,0 +1,98 @@
+#pragma once
+
+#include <windows.h>
+#include <bfc/platform/types.h>
+#include <vector>
+#include "../autolock.h"
+#include "ThreadID.h"
+#include "ThreadFunctions.h"
+#include "threadpool_types.h"
+/* random notes
+
+HANDLEs common to all threads
+
+WaitForMultipleObjectsEx() around these
+0 - killswitch
+1 - shared APC event. since threads might want to use APCs themselves, we'll use a different mechanism (thread-safe FIFO and an event). the intention is that APCs that can go on any thread will use this handle
+2 - per thread APC event.
+
+
+parameters for "run my function" method
+function pointer, user data, flags
+flags:
+interrupt - for very short non-locking functions where it is safe to interrupt another thread, uses QueueUserAPC
+no_wait - spawn a new thread if all threads are busy
+com_multithreaded - all threads are created with CoInitialize(0), if you need a COINIT_MULTITHREADED thread, use this flag
+
+parameters for "add my handle" method
+handle, function pointer, user data, flags
+flags:
+single_thread - only one thread in the pool will wait on your object, useful if your handle is not auto-reset
+
+parameters for "function call repeat" - calls your function until you return 0
+function pointer, user data, flags
+flags:
+single_thread - keep calling on the same thread
+*/
+
+
+class ThreadPool : public api_threadpool
+{
+public:
+ static const char *getServiceName() { return "Thread Pool API"; }
+ static const GUID getServiceGuid() { return ThreadPoolGUID; }
+public:
+ // Owner API:
+ ThreadPool();
+ void Kill();
+
+ // User API:
+ /* If you have multiple events, APCs, etc and you need them to always run on the same thread
+ you can reserve one */
+ ThreadID *ReserveThread(int flags);
+ /* Release a thread you've previously reserved */
+ void ReleaseThread(ThreadID *thread_id);
+
+ /* adds a waitable handle to the thread pool. when the event is signalled, your function ptr will get called
+ user_data and id values get passed to your function.
+ your function should return 1 to indicate that it can be removed
+ flags, see api_threadpool */
+ int AddHandle(ThreadID *threadid, HANDLE handle, api_threadpool::ThreadPoolFunc func, void *user_data, intptr_t id, int flags);
+ void RemoveHandle(ThreadID *threadid, HANDLE handle);
+ int RunFunction(ThreadID *threadid, api_threadpool::ThreadPoolFunc func, void *user_data, intptr_t id, int flags);
+
+ size_t GetNumberOfThreads(); // total number of threads in the threadpool
+ size_t GetNumberOfActiveThreads(); // number of threads that are currently being used (inside user function but not necessarily busy)
+
+private:
+ enum
+ {
+ TYPE_MT = 0,
+ TYPE_STA = 1,
+ TYPE_MT_RESERVED = 2,
+ TYPE_STA_RESERVED = 3,
+
+ THREAD_TYPES = 4, // two thread types, single threaded apartment COM and multithreaded COM
+ };
+private:
+ static DWORD CALLBACK WatchDogThreadProcedure_stub(LPVOID param);
+ ThreadID *CreateNewThread_Internal(int thread_type = 0);
+ DWORD CALLBACK WatchDogThreadProcedure();
+ static int GetThreadType(int flags, int reserved = 0);
+ static void GetThreadTypes(int flags, bool types[THREAD_TYPES]);
+ void RemoveHandle_Internal(size_t start, HANDLE handle); // recursive helper function for RemoveHandle()
+ void AddHandle_Internal(size_t start, HANDLE handle, int flags); // recursive helper function for RemoveHandle()
+
+ Nullsoft::Utility::LockGuard guard; // guards threads, any_thread_handles, and non_reserved_handles data structures
+ typedef std::vector<ThreadID*> ThreadList;
+ ThreadList threads;
+ ThreadPoolTypes::HandleList any_thread_handles[THREAD_TYPES];
+ HANDLE killswitch;
+ HANDLE watchdog_thread_handle;
+ volatile LONG num_threads_available[THREAD_TYPES];
+ ThreadFunctions thread_functions;
+ HANDLE max_load_event[THREAD_TYPES];
+protected:
+ RECVS_DISPATCH;
+};
+