1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798 |
- #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;
- };
|