Skip to content

Commit 1a63f5a

Browse files
committed
multiple tasks support
1 parent 7ed614c commit 1a63f5a

File tree

1 file changed

+79
-17
lines changed

1 file changed

+79
-17
lines changed

12_MeshLoaders/main.cpp

Lines changed: 79 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,70 @@
1010
#include "nbl/ext/MitsubaLoader/CSerializedLoader.h"
1111
#endif
1212

13+
class ThreadPool
14+
{
15+
public:
16+
ThreadPool(size_t numThreads = 4)
17+
{
18+
for (size_t i = 0; i < numThreads; i++)
19+
m_workers.emplace_back(
20+
[this]
21+
{
22+
while (true)
23+
{
24+
std::function<void()> task;
25+
{
26+
std::unique_lock lock(m_queueMutex);
27+
m_taskReady.wait(lock, [this] { return m_stop.load() || !m_tasks.empty(); });
28+
if (m_stop.load() && m_tasks.empty())
29+
return;
30+
31+
task = std::move(m_tasks.front());
32+
m_tasks.pop();
33+
}
34+
35+
task();
36+
}
37+
}
38+
);
39+
}
40+
41+
template <typename Function, typename... Args>
42+
auto enqueue(Function&& func, Args&& ...args) -> std::future<std::invoke_result_t<Function, Args...>>
43+
{
44+
using ret_t = std::invoke_result_t<Function, Args...>;
45+
46+
auto task = std::bind(std::forward<Function>(func), std::forward<Args>(args)...);
47+
auto taskPtr = std::make_shared<std::packaged_task<ret_t()>>(std::move(task));
48+
49+
std::future<ret_t> future = taskPtr->get_future();
50+
51+
{
52+
std::unique_lock lock(m_queueMutex);
53+
m_tasks.emplace([taskPtr]() { (*taskPtr)(); });
54+
}
55+
56+
m_taskReady.notify_one();
57+
return future;
58+
}
59+
60+
~ThreadPool()
61+
{
62+
m_stop.store(true);
63+
m_taskReady.notify_all();
64+
for (auto& worker : m_workers)
65+
worker.join();
66+
}
67+
68+
private:
69+
std::vector<std::thread> m_workers;
70+
std::queue<std::function<void()>> m_tasks;
71+
72+
std::mutex m_queueMutex;
73+
std::condition_variable m_taskReady;
74+
std::atomic<bool> m_stop;
75+
};
76+
1377
class MeshLoadersApp final : public MonoWindowApplication, public BuiltinResourcesApplication
1478
{
1579
using device_base_t = MonoWindowApplication;
@@ -217,10 +281,17 @@ class MeshLoadersApp final : public MonoWindowApplication, public BuiltinResourc
217281

218282
inline bool onAppTerminated() override
219283
{
220-
if (m_saveGeomTaskFuture.valid())
284+
m_logger->log("Waiting for all geometry saving tasks (%u) to complete...", ILogger::ELL_INFO, m_saveGeomTaskFutures.size());
285+
286+
for (size_t i = 0; i < m_saveGeomTaskFutures.size(); i++)
221287
{
222-
m_logger->log("Waiting for geometry writer to finish writing...", ILogger::ELL_INFO);
223-
m_saveGeomTaskFuture.wait();
288+
const auto& task = m_saveGeomTaskFutures[i];
289+
290+
if (!task.valid())
291+
continue;
292+
293+
task.wait();
294+
m_logger->log("Task %u of %u completed!", ILogger::ELL_INFO, i+1, m_saveGeomTaskFutures.size());
224295
}
225296

226297
return device_base_t::onAppTerminated();
@@ -321,19 +392,9 @@ class MeshLoadersApp final : public MonoWindowApplication, public BuiltinResourc
321392

322393
if (m_saveGeom)
323394
{
324-
if (m_saveGeomTaskFuture.valid())
325-
{
326-
m_logger->log("Waiting for previous geometry saving task to complete...", ILogger::ELL_INFO);
327-
m_saveGeomTaskFuture.wait();
328-
}
329-
330-
std::string currentGeomSavePath = m_specifiedGeomSavePath.value_or((m_saveGeomPrefixPath / path(m_modelPath).filename()).generic_string());
331-
m_saveGeomTaskFuture = std::async(
332-
std::launch::async,
333-
[this, geometries, currentGeomSavePath] { writeGeometry(
334-
geometries[0],
335-
currentGeomSavePath
336-
); }
395+
std::string savePath = m_specifiedGeomSavePath.value_or((m_saveGeomPrefixPath / path(m_modelPath).filename()).generic_string());
396+
m_saveGeomTaskFutures.emplace_back(
397+
m_threadPool->enqueue([this, geometries, savePath] { writeGeometry(geometries[0], savePath); })
337398
);
338399
}
339400

@@ -496,7 +557,8 @@ class MeshLoadersApp final : public MonoWindowApplication, public BuiltinResourc
496557
std::string m_modelPath;
497558

498559
bool m_saveGeom = false;
499-
std::future<void> m_saveGeomTaskFuture;
560+
std::unique_ptr<ThreadPool> m_threadPool = std::make_unique<ThreadPool>(3);
561+
std::vector<std::future<void>> m_saveGeomTaskFutures;
500562
std::optional<const std::string> m_specifiedGeomSavePath;
501563
nbl::system::path m_saveGeomPrefixPath;
502564
};

0 commit comments

Comments
 (0)