DotNetDupe 4.0.6
C++17/20 Implementation of the .NET Base Class Library (BCL)
Loading...
Searching...
No Matches
ThreadPool.cpp
Go to the documentation of this file.
1#include "pch.h"
10
11namespace DotNetDupe {
12 namespace System {
13 namespace Threading {
14
17 struct ThreadPoolTask {
18 WaitCallback Callback;
19 Object* State;
20 };
21
25 class ThreadPoolInternal {
26 public:
27 static ThreadPoolInternal& GetInstance() {
29 static ThreadPoolInternal instance;
30 return instance;
31 }
32
33 bool QueueTask(WaitCallback callback, Object* pState) {
35 {
36 Lock<CriticalSection> lock(m_csSync);
37 if (m_bIsShuttingDown) return false;
38
39 ThreadPoolTask objTask;
40 objTask.Callback = callback;
41 objTask.State = pState;
42 m_qTasks.Add(objTask);
43 }
45 m_evtWorkAvailable.Set();
46 return true;
47 }
48
49 bool SetMinThreads(int iMinThreads) {
51 if (iMinThreads <= 0) return false;
52 Lock<CriticalSection> lock(m_csSync);
53 if (m_bIsShuttingDown) return false;
55 while (m_pvWorkerThreads.GetCount() < iMinThreads) {
56 SmartPointer<Thread> pWorker = SmartPointer<Thread>::NewShared(ThreadStart([this]() { WorkerLoop(); }));
57 pWorker->Start();
58 m_pvWorkerThreads.Add(std::move(pWorker));
59 }
60 return true;
61 }
62
63 private:
64 ThreadPoolInternal()
65 : m_bIsShuttingDown(false), m_evtWorkAvailable(false, false) {
67 int iThreadCount = Environment::GetProcessorCount();
68 if (iThreadCount < 10) iThreadCount = 10;
69
70 for (int i = 0; i < iThreadCount; ++i) {
71 SmartPointer<Thread> pWorker = SmartPointer<Thread>::NewShared(ThreadStart([this]() { WorkerLoop(); }));
72 pWorker->Start();
73 m_pvWorkerThreads.Add(std::move(pWorker));
74 }
75 }
76
77 ~ThreadPoolInternal() {
79 {
80 Lock<CriticalSection> lock(m_csSync);
81 m_bIsShuttingDown = true;
82 }
83 // Wake up all threads so they can exit.
84 // AutoResetEvent only wakes one per Set(), so we need to set it for each thread.
85 for (int i = 0; i < m_pvWorkerThreads.GetCount(); ++i) {
86 m_evtWorkAvailable.Set();
87 }
88
89 for (int i = 0; i < m_pvWorkerThreads.GetCount(); ++i) {
90 SmartPointer<Thread> pWorker = m_pvWorkerThreads[i];
91 if (!pWorker.IsNull()) {
92 pWorker->Join();
93 }
94 }
95 }
96
97 void WorkerLoop() {
99 while (true) {
100 ThreadPoolTask objTask;
101 bool bHasTask = false;
102
103 {
104 Lock<CriticalSection> lock(m_csSync);
105 if (m_qTasks.GetCount() > 0) {
106 objTask = m_qTasks[0];
107 m_qTasks.RemoveAt(0);
108 bHasTask = true;
109
110 // If there's more work, signal another thread
111 if (m_qTasks.GetCount() > 0) {
112 m_evtWorkAvailable.Set();
113 }
114 } else if (m_bIsShuttingDown) {
115 // Signal the next thread to wake up and exit
116 m_evtWorkAvailable.Set();
117 return;
118 }
119 }
120
121 if (bHasTask) {
122 if (objTask.Callback) {
123 try {
124 objTask.Callback(objTask.State);
125 } catch (const Exception&) {
126 // DotNetDupe exception
127 } catch (const std::exception& ex) {
128 (void)UnknownException(ex.what());
129 } catch (...) {
130 (void)UnknownException("An unhandled exception occurred during ThreadPool task execution.");
131 }
132 }
133 } else {
134 // Wait for work or shutdown signal
135 m_evtWorkAvailable.WaitOne();
136 }
137 }
138 }
139
140 Collections::Generic::List<SmartPointer<Thread>> m_pvWorkerThreads;
141 Collections::Generic::List<ThreadPoolTask> m_qTasks;
142 CriticalSection m_csSync;
143 EventWaitHandle m_evtWorkAvailable;
144 bool m_bIsShuttingDown;
145 };
146
149 return QueueUserWorkItem(callback, nullptr);
150 }
151
154 return ThreadPoolInternal::GetInstance().QueueTask(callback, pState);
155 }
156
157 bool ThreadPool::SetMinThreads(int iMinThreads) {
159 return ThreadPoolInternal::GetInstance().SetMinThreads(iMinThreads);
160 }
161 }
162 }
163}
Provides a re-entrant mutual exclusion primitive for thread synchronization.
Provides information about, and means to manipulate, the current environment and platform.
Represents a thread synchronization event supporting automatic and manual reset modes.
Represents a strongly typed list of objects that can be accessed by index mirroring ....
Provides an RAII-style scoped lock wrapper around synchronization primitives.
Creates and controls a thread, sets its priority, and gets its status mirroring .NET System....
Provides a pool of threads that can be used to execute tasks and work items.
Represents an unknown or unmapped exception encountered during execution.
static int GetProcessorCount()
Gets the number of logical processors available on the current machine.
Supports all classes in the DotNetDupe class hierarchy.
Definition Object.h:18
static SmartPointer< T > NewShared()
Creates a Shared SmartPointer, default constructing T.
static bool SetMinThreads(int iMinThreads)
Sets the minimum number of threads the thread pool creates on demand as new requests are made.
static bool QueueUserWorkItem(WaitCallback callback)
Queues a method for execution. The method executes when a thread pool thread becomes available.
UnknownException()
Initializes a new instance of the UnknownException class with a default message.
Definition Exception.cpp:53
Action< Object * > WaitCallback
Represents a callback method to be executed by a thread pool thread.
Definition ThreadPool.h:16