Working on multi-threading, including web
This commit is contained in:
parent
b055faf882
commit
648acf8938
@ -474,6 +474,8 @@ add_executable(space-game001
|
||||
src/planet/PlanetData.h
|
||||
src/utils/Perlin.cpp
|
||||
src/utils/Perlin.h
|
||||
src/utils/TaskManager.cpp
|
||||
src/utils/TaskManager.h
|
||||
src/planet/StoneObject.cpp
|
||||
src/planet/StoneObject.h
|
||||
src/render/FrameBuffer.cpp
|
||||
@ -491,6 +493,7 @@ set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT s
|
||||
target_include_directories(space-game001 PRIVATE
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/external"
|
||||
"C:/Boost/include/boost-1_84"
|
||||
)
|
||||
|
||||
set_target_properties(space-game001 PROPERTIES
|
||||
@ -501,6 +504,7 @@ set_target_properties(space-game001 PROPERTIES
|
||||
# PNG_ENABLED – включает код PNG в TextureManager
|
||||
# SDL_MAIN_HANDLED – отключает переопределение main -> SDL_main
|
||||
target_compile_definitions(space-game001 PRIVATE
|
||||
WIN32_LEAN_AND_MEAN
|
||||
PNG_ENABLED
|
||||
SDL_MAIN_HANDLED
|
||||
SIMPLIFIED
|
||||
|
||||
@ -157,7 +157,7 @@ emrun --no_browser --port 8080 .
|
||||
|
||||
# Emscripten new
|
||||
```
|
||||
emcc src/main.cpp src/Game.cpp src/Environment.cpp src/BoneAnimatedModel.cpp src/TextModel.cpp src/Projectile.cpp src/SparkEmitter.cpp src/UiManager.cpp src/render/Renderer.cpp src/render/ShaderManager.cpp src/render/TextureManager.cpp src/render/FrameBuffer.cpp src/render/OpenGlExtensions.cpp src/utils/Utils.cpp src/utils/Perlin.cpp src/planet/PlanetData.cpp src/planet/PlanetObject.cpp src/planet/StoneObject.cpp -O2 -std=c++17 -pthread -sUSE_PTHREADS=1 -sPTHREAD_POOL_SIZE=4 -sTOTAL_MEMORY=4294967296 -sINITIAL_MEMORY=3221225472 -sMAXIMUM_MEMORY=4294967296 -sALLOW_MEMORY_GROWTH=1 -I./thirdparty1/eigen-5.0.0 -I./src -I./thirdparty/libzip-1.11.3/build-emcmake/install/include -L./thirdparty/libzip-1.11.3/build-emcmake/install/lib -lzip -lz -sUSE_SDL_IMAGE=2 -sUSE_SDL=2 -sUSE_LIBPNG=1 -DSIMPLIFIED=1 --preload-file space-game001x.zip -o space-game001.html
|
||||
emcc src/main.cpp src/Game.cpp src/Environment.cpp src/BoneAnimatedModel.cpp src/TextModel.cpp src/Projectile.cpp src/SparkEmitter.cpp src/UiManager.cpp src/render/Renderer.cpp src/render/ShaderManager.cpp src/render/TextureManager.cpp src/render/FrameBuffer.cpp src/render/OpenGlExtensions.cpp src/utils/Utils.cpp src/utils/TaskManager.cpp src/utils/Perlin.cpp src/planet/PlanetData.cpp src/planet/PlanetObject.cpp src/planet/StoneObject.cpp -O2 -std=c++17 -pthread -sUSE_PTHREADS=1 -sPTHREAD_POOL_SIZE=4 -sTOTAL_MEMORY=4294967296 -sINITIAL_MEMORY=3221225472 -sMAXIMUM_MEMORY=4294967296 -sALLOW_MEMORY_GROWTH=1 -fexceptions -I./thirdparty1/eigen-5.0.0 -I./src -I./thirdparty/libzip-1.11.3/build-emcmake/install/include -IC:/Boost/include/boost-1_84 -L./thirdparty/libzip-1.11.3/build-emcmake/install/lib -lzip -lz -sUSE_SDL_IMAGE=2 -sUSE_SDL=2 -sUSE_LIBPNG=1 -DSIMPLIFIED=1 --preload-file space-game001.zip -o space-game001.html
|
||||
```
|
||||
|
||||
# License
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
namespace ZL
|
||||
{
|
||||
#ifdef EMSCRIPTEN
|
||||
const char* CONST_ZIP_FILE = "space-game001a.zip";
|
||||
const char* CONST_ZIP_FILE = "space-game001.zip";
|
||||
#else
|
||||
const char* CONST_ZIP_FILE = "";
|
||||
#endif
|
||||
@ -343,6 +343,8 @@ namespace ZL
|
||||
std::cout << "Init step 6 " << std::endl;
|
||||
planetObject.init();
|
||||
|
||||
planetObject.taskManager = &taskManager;
|
||||
|
||||
std::cout << "Init step 7 " << std::endl;
|
||||
//rockTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/rock.png", CONST_ZIP_FILE));
|
||||
|
||||
|
||||
@ -7,6 +7,8 @@
|
||||
#include "planet/PlanetObject.h"
|
||||
#include "UiManager.h"
|
||||
#include "Projectile.h"
|
||||
#include "utils/TaskManager.h"
|
||||
#include <queue>
|
||||
|
||||
namespace ZL {
|
||||
|
||||
@ -103,6 +105,11 @@ namespace ZL {
|
||||
uint64_t lastProjectileFireTime = 0;
|
||||
int maxProjectiles = 32;
|
||||
std::vector<Vector3f> shipLocalEmissionPoints;
|
||||
|
||||
TaskManager taskManager;
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -51,12 +51,9 @@ namespace ZL {
|
||||
planetMeshLods[i].Move(PLANET_CENTER_OFFSET);
|
||||
}
|
||||
|
||||
|
||||
//#ifndef SIMPLIFIED
|
||||
planetAtmosphereLod = generateSphere(5, 0);
|
||||
planetAtmosphereLod.Scale(PLANET_RADIUS * 1.03);
|
||||
planetAtmosphereLod.Move(PLANET_CENTER_OFFSET);
|
||||
//#endif
|
||||
}
|
||||
|
||||
const LodLevel& PlanetData::getLodLevel(int level) const {
|
||||
|
||||
@ -26,7 +26,7 @@ namespace ZL {
|
||||
VertexID generateEdgeID(const VertexID& id1, const VertexID& id2);
|
||||
|
||||
#ifdef SIMPLIFIED
|
||||
constexpr static int MAX_LOD_LEVELS = 1;
|
||||
constexpr static int MAX_LOD_LEVELS = 6;
|
||||
#else
|
||||
constexpr static int MAX_LOD_LEVELS = 6;
|
||||
#endif
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
#include "render/OpenGlExtensions.h"
|
||||
#include "Environment.h"
|
||||
#include "StoneObject.h"
|
||||
|
||||
#include "utils/TaskManager.h"
|
||||
|
||||
namespace ZL {
|
||||
|
||||
@ -77,20 +77,18 @@ namespace ZL {
|
||||
sandTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/sand2.png", CONST_ZIP_FILE));
|
||||
stoneTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/rock.png", CONST_ZIP_FILE));
|
||||
|
||||
|
||||
//#ifndef SIMPLIFIED
|
||||
// Атмосфера
|
||||
planetAtmosphereRenderStruct.data = planetData.getAtmosphereLod().vertexData;
|
||||
if (planetAtmosphereRenderStruct.data.PositionData.size() > 0)
|
||||
{
|
||||
planetAtmosphereRenderStruct.RefreshVBO();
|
||||
}
|
||||
//#endif
|
||||
|
||||
|
||||
planetStones = CreateStoneGroupData(778, planetData.getLodLevel(lodIndex));
|
||||
|
||||
stonesToRender = planetStones.inflate(planetStones.allInstances.size());
|
||||
//stonesToRender = planetStones.inflate(planetStones.allInstances.size());
|
||||
stonesToRender.resize(planetStones.allInstances.size());
|
||||
planetStones.initStatuses();
|
||||
|
||||
stoneToBake = planetStones.inflateOne(0, 0.75);
|
||||
}
|
||||
@ -98,6 +96,75 @@ namespace ZL {
|
||||
|
||||
void PlanetObject::update(float deltaTimeMs) {
|
||||
|
||||
// 1. Проверка порога движения (оптимизация из текущего кода)
|
||||
float movementThreshold = 1.0f;
|
||||
if ((Environment::shipPosition - lastUpdatePos).squaredNorm() < movementThreshold * movementThreshold
|
||||
&& !triangleIndicesToDraw.empty()) {
|
||||
processMainThreadTasks(); // Все равно обрабатываем очередь OpenGL задач
|
||||
return;
|
||||
}
|
||||
lastUpdatePos = Environment::shipPosition;
|
||||
|
||||
// 2. Получаем список видимых треугольников
|
||||
auto newIndices = planetData.getTrianglesUnderCameraNew2(Environment::shipPosition);
|
||||
std::sort(newIndices.begin(), newIndices.end());
|
||||
|
||||
// 3. Анализируем, что нужно загрузить
|
||||
for (int triIdx : newIndices) {
|
||||
if (planetStones.statuses[triIdx] == ChunkStatus::Empty) {
|
||||
// Помечаем, чтобы не спамить задачами
|
||||
planetStones.statuses[triIdx] = ChunkStatus::Generating;
|
||||
|
||||
// Отправляем тяжелую математику в TaskManager
|
||||
taskManager->EnqueueBackgroundTask([this, triIdx]() {
|
||||
// Выполняется в фоновом потоке: только генерация геометрии в RAM
|
||||
float scaleModifier = 1.0f;
|
||||
VertexDataStruct generatedData = planetStones.inflateOneDataOnly(triIdx, scaleModifier);
|
||||
|
||||
// Передаем задачу на загрузку в GPU в очередь главного потока
|
||||
this->EnqueueMainThreadTask([this, triIdx, data = std::move(generatedData)]() mutable {
|
||||
// Проверяем актуальность: если треугольник всё еще в списке видимых
|
||||
auto it = std::find(triangleIndicesToDraw.begin(), triangleIndicesToDraw.end(), triIdx);
|
||||
if (it != triangleIndicesToDraw.end()) {
|
||||
stonesToRender[triIdx].data = std::move(data);
|
||||
stonesToRender[triIdx].RefreshVBO(); // OpenGL вызов
|
||||
planetStones.statuses[triIdx] = ChunkStatus::Live;
|
||||
}
|
||||
else {
|
||||
// Если уже не нужен — просто сбрасываем статус
|
||||
planetStones.statuses[triIdx] = ChunkStatus::Empty;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Очистка (Unload)
|
||||
// Если статус Live, но треугольника нет в новых индексах — освобождаем GPU память
|
||||
for (size_t i = 0; i < planetStones.statuses.size(); ++i) {
|
||||
if (planetStones.statuses[i] == ChunkStatus::Live) {
|
||||
bool isVisible = std::binary_search(newIndices.begin(), newIndices.end(), (int)i);
|
||||
if (!isVisible) {
|
||||
// Очищаем данные и VBO (деструкторы shared_ptr в VertexRenderStruct сделают glDeleteBuffers)
|
||||
stonesToRender[i].data.PositionData.clear();
|
||||
stonesToRender[i].vao.reset();
|
||||
stonesToRender[i].positionVBO.reset();
|
||||
stonesToRender[i].normalVBO.reset();
|
||||
stonesToRender[i].tangentVBO.reset();
|
||||
stonesToRender[i].binormalVBO.reset();
|
||||
stonesToRender[i].colorVBO.reset();
|
||||
stonesToRender[i].texCoordVBO.reset();
|
||||
|
||||
planetStones.statuses[i] = ChunkStatus::Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
triangleIndicesToDraw = std::move(newIndices);
|
||||
|
||||
// 5. Выполняем одну задачу из очереди OpenGL (RefreshVBO и т.д.)
|
||||
processMainThreadTasks();
|
||||
/*
|
||||
float movementThreshold = 1.0f;
|
||||
if ((Environment::shipPosition - lastUpdatePos).squaredNorm() < movementThreshold * movementThreshold && !triangleIndicesToDraw.empty()) {
|
||||
return;
|
||||
@ -111,7 +178,7 @@ namespace ZL {
|
||||
|
||||
if (newIndices != triangleIndicesToDraw) {
|
||||
triangleIndicesToDraw = std::move(newIndices);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
|
||||
@ -205,7 +272,6 @@ namespace ZL {
|
||||
|
||||
void PlanetObject::draw(Renderer& renderer) {
|
||||
|
||||
//#ifndef SIMPLIFIED
|
||||
{
|
||||
if (stoneMapFB == nullptr)
|
||||
{
|
||||
@ -221,10 +287,6 @@ namespace ZL {
|
||||
stoneMapFB->GenerateMipmaps();
|
||||
|
||||
}
|
||||
//#endif
|
||||
|
||||
|
||||
//bakeStoneTexture(renderer);
|
||||
|
||||
glViewport(0, 0, Environment::width, Environment::height);
|
||||
//--------------------------
|
||||
@ -232,10 +294,7 @@ namespace ZL {
|
||||
|
||||
drawPlanet(renderer);
|
||||
drawStones(renderer);
|
||||
|
||||
//#ifndef SIMPLIFIED
|
||||
drawAtmosphere(renderer);
|
||||
//#endif
|
||||
}
|
||||
|
||||
void PlanetObject::drawPlanet(Renderer& renderer)
|
||||
@ -382,7 +441,7 @@ namespace ZL {
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glBindTexture(GL_TEXTURE_2D, stoneTexture->getTexID());
|
||||
|
||||
|
||||
/*
|
||||
for (int i : triangleIndicesToDraw)
|
||||
//for (int i = 0; i < stonesToRender.size(); i++)
|
||||
{
|
||||
@ -390,7 +449,20 @@ namespace ZL {
|
||||
{
|
||||
renderer.DrawVertexRenderStruct(stonesToRender[i]);
|
||||
}
|
||||
}*/
|
||||
for (int i : triangleIndicesToDraw) {
|
||||
// КРИТИЧЕСКОЕ ИЗМЕНЕНИЕ:
|
||||
// Проверяем, что данные не просто существуют, а загружены в GPU
|
||||
if (planetStones.statuses[i] == ChunkStatus::Live) {
|
||||
// Дополнительная проверка на наличие данных (на всякий случай)
|
||||
if (stonesToRender[i].data.PositionData.size() > 0) {
|
||||
renderer.DrawVertexRenderStruct(stonesToRender[i]);
|
||||
}
|
||||
}
|
||||
// Если статус Generating или Empty — мы просто пропускаем этот индекс.
|
||||
// Камни появятся на экране плавно, как только отработает TaskManager и RefreshVBO.
|
||||
}
|
||||
|
||||
CheckGlError();
|
||||
glDisable(GL_BLEND);
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
||||
@ -16,8 +16,11 @@
|
||||
#include "PlanetData.h"
|
||||
#include "StoneObject.h"
|
||||
#include "render/FrameBuffer.h"
|
||||
#include <queue>
|
||||
#include <mutex>
|
||||
|
||||
namespace ZL {
|
||||
class TaskManager;
|
||||
|
||||
class PlanetObject {
|
||||
public:
|
||||
@ -39,6 +42,8 @@ namespace ZL {
|
||||
|
||||
Vector3f lastUpdatePos;
|
||||
|
||||
TaskManager* taskManager = nullptr;
|
||||
|
||||
public:
|
||||
PlanetObject();
|
||||
|
||||
@ -51,6 +56,32 @@ namespace ZL {
|
||||
void drawAtmosphere(Renderer& renderer);
|
||||
|
||||
float distanceToPlanetSurface(const Vector3f& viewerPosition);
|
||||
|
||||
std::queue<std::function<void()>> mainThreadTasks;
|
||||
std::mutex mainThreadMutex;
|
||||
|
||||
void EnqueueMainThreadTask(std::function<void()> task) {
|
||||
std::lock_guard<std::mutex> lock(mainThreadMutex);
|
||||
mainThreadTasks.push(task);
|
||||
}
|
||||
|
||||
// Выполнение задач по одной (или пачкой) за кадр
|
||||
void processMainThreadTasks() {
|
||||
std::function<void()> task;
|
||||
|
||||
// Извлекаем только одну задачу, чтобы не блокировать update надолго
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mainThreadMutex);
|
||||
if (!mainThreadTasks.empty()) {
|
||||
task = std::move(mainThreadTasks.front());
|
||||
mainThreadTasks.pop();
|
||||
}
|
||||
}
|
||||
|
||||
if (task) {
|
||||
task(); // Здесь выполняется RefreshVBO или загрузка текстуры
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ZL
|
||||
@ -16,13 +16,20 @@ namespace ZL {
|
||||
|
||||
|
||||
#ifdef SIMPLIFIED
|
||||
const float StoneParams::BASE_SCALE = 10.0f; // Общий размер камня
|
||||
const float StoneParams::MIN_AXIS_SCALE = 1.0f; // Минимальное растяжение/сжатие по оси
|
||||
const float StoneParams::MAX_AXIS_SCALE = 1.0f; // Максимальное растяжение/сжатие по оси
|
||||
const float StoneParams::MIN_PERTURBATION = 0.0f; // Минимальное радиальное возмущение вершины
|
||||
const float StoneParams::MAX_PERTURBATION = 0.0f; // Максимальное радиальное возмущение вершины
|
||||
const int StoneParams::STONES_PER_TRIANGLE = 40;
|
||||
/*
|
||||
const float StoneParams::BASE_SCALE = 1000.0f; // Общий размер камня
|
||||
const float StoneParams::MIN_AXIS_SCALE = 1.0f; // Минимальное растяжение/сжатие по оси
|
||||
const float StoneParams::MAX_AXIS_SCALE = 1.0f; // Максимальное растяжение/сжатие по оси
|
||||
const float StoneParams::MIN_PERTURBATION = 0.0f; // Минимальное радиальное возмущение вершины
|
||||
const float StoneParams::MAX_PERTURBATION = 0.0f; // Максимальное радиальное возмущение вершины
|
||||
const int StoneParams::STONES_PER_TRIANGLE = 2;
|
||||
|
||||
*/
|
||||
#else
|
||||
const float StoneParams::BASE_SCALE = 10.0f; // Общий размер камня
|
||||
const float StoneParams::MIN_AXIS_SCALE = 1.0f; // Минимальное растяжение/сжатие по оси
|
||||
@ -297,34 +304,12 @@ namespace ZL {
|
||||
|
||||
std::vector<VertexRenderStruct> StoneGroup::inflate(int count)
|
||||
{
|
||||
//static VertexDataStruct baseStone = CreateBaseConvexPolyhedron(1337);
|
||||
|
||||
std::vector<VertexRenderStruct> result;
|
||||
result.resize(count);
|
||||
|
||||
for (int tIdx = 0; tIdx < count; tIdx++)
|
||||
{
|
||||
result[tIdx] = inflateOne(tIdx, 1.0f);
|
||||
/*
|
||||
for (const auto& inst : allInstances[tIdx]) {
|
||||
Matrix3f rotMat = QuatToMatrix(inst.rotation);
|
||||
|
||||
for (size_t j = 0; j < baseStone.PositionData.size(); ++j) {
|
||||
Vector3f p = baseStone.PositionData[j];
|
||||
Vector3f n = baseStone.NormalData[j];
|
||||
|
||||
p.v[0] *= inst.scale.v[0];
|
||||
p.v[1] *= inst.scale.v[1];
|
||||
p.v[2] *= inst.scale.v[2];
|
||||
|
||||
result[tIdx].data.PositionData.push_back(MultMatrixVector(rotMat, p) + inst.position);
|
||||
result[tIdx].data.NormalData.push_back(MultMatrixVector(rotMat, n));
|
||||
result[tIdx].data.TexCoordData.push_back(baseStone.TexCoordData[j]);
|
||||
|
||||
}
|
||||
|
||||
result[tIdx].RefreshVBO();
|
||||
}*/
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -361,4 +346,33 @@ namespace ZL {
|
||||
return result;
|
||||
}
|
||||
|
||||
VertexDataStruct StoneGroup::inflateOneDataOnly(int index, float scaleModifier)
|
||||
{
|
||||
static VertexDataStruct baseStone = CreateBaseConvexPolyhedron(1337);
|
||||
|
||||
VertexDataStruct result;
|
||||
|
||||
|
||||
for (const auto& inst : allInstances[index]) {
|
||||
Matrix3f rotMat = inst.rotation.toRotationMatrix();
|
||||
|
||||
for (size_t j = 0; j < baseStone.PositionData.size(); ++j) {
|
||||
Vector3f p = baseStone.PositionData[j];
|
||||
Vector3f n = baseStone.NormalData[j];
|
||||
|
||||
p(0) *= inst.scale(0) * scaleModifier;
|
||||
p(1) *= inst.scale(1) * scaleModifier;
|
||||
p(2) *= inst.scale(2) * scaleModifier;
|
||||
|
||||
result.PositionData.push_back(rotMat * p + inst.position);
|
||||
result.NormalData.push_back(rotMat * n);
|
||||
result.TexCoordData.push_back(baseStone.TexCoordData[j]);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace ZL
|
||||
|
||||
@ -22,6 +22,13 @@ namespace ZL {
|
||||
Eigen::Quaternionf rotation;
|
||||
};
|
||||
|
||||
enum class ChunkStatus {
|
||||
Empty, // Äàííûõ íåò
|
||||
Generating, // Çàäà÷à â TaskManager (CPU)
|
||||
ReadyToUpload, // Äàííûå â ïàìÿòè, æäóò î÷åðåäè â ãëàâíûé ïîòîê
|
||||
Live // Çàãðóæåíî â GPU è ãîòîâî ê îòðèñîâêå
|
||||
};
|
||||
|
||||
struct StoneGroup {
|
||||
// mesh.PositionData è ïðî÷èå áóäóò çàïîëíÿòüñÿ â inflate()
|
||||
VertexDataStruct mesh;
|
||||
@ -32,6 +39,14 @@ namespace ZL {
|
||||
std::vector<VertexRenderStruct> inflate(int count);
|
||||
|
||||
VertexRenderStruct inflateOne(int index, float scaleModifier);
|
||||
VertexDataStruct inflateOneDataOnly(int index, float scaleModifier);
|
||||
|
||||
std::vector<ChunkStatus> statuses;
|
||||
|
||||
// Èíèöèàëèçàöèÿ ñòàòóñîâ ïðè ñîçäàíèè ãðóïïû
|
||||
void initStatuses() {
|
||||
statuses.assign(allInstances.size(), ChunkStatus::Empty);
|
||||
}
|
||||
};
|
||||
|
||||
// Òåïåðü âîçâðàùàåò çàãîòîâêó ñî âñåìè ïàðàìåòðàìè, íî áåç òÿæåëîãî ìåøà
|
||||
|
||||
0
src/utils/TaskManager.cpp
Normal file
0
src/utils/TaskManager.cpp
Normal file
43
src/utils/TaskManager.h
Normal file
43
src/utils/TaskManager.h
Normal file
@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
#include <boost/asio.hpp>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
#include <memory>
|
||||
|
||||
namespace ZL {
|
||||
|
||||
class TaskManager {
|
||||
private:
|
||||
boost::asio::io_context ioContext;
|
||||
std::unique_ptr<boost::asio::executor_work_guard<boost::asio::io_context::executor_type>> workGuard;
|
||||
std::vector<std::thread> workers;
|
||||
|
||||
public:
|
||||
//TaskManager(size_t threadCount = std::thread::hardware_concurrency()) {
|
||||
TaskManager(size_t threadCount = 2) {
|
||||
workGuard = std::make_unique<boost::asio::executor_work_guard<boost::asio::io_context::executor_type>>(ioContext.get_executor());
|
||||
|
||||
for (size_t i = 0; i < threadCount; ++i) {
|
||||
workers.emplace_back([this]() {
|
||||
ioContext.run();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Ìåòîä äëÿ äîáàâëåíèÿ ôîíîâîé çàäà÷è
|
||||
void EnqueueBackgroundTask(std::function<void()> task) {
|
||||
boost::asio::post(ioContext, task);
|
||||
}
|
||||
|
||||
// Graceful shutdown
|
||||
~TaskManager() {
|
||||
workGuard.reset(); // Ðàçðåøàåì ioContext.run() çàâåðøèòüñÿ, êîãäà çàäà÷ íå îñòàíåòñÿ
|
||||
ioContext.stop(); // Îïöèîíàëüíî: íåìåäëåííàÿ îñòàíîâêà
|
||||
for (auto& t : workers) {
|
||||
if (t.joinable()) t.join();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ZL
|
||||
Loading…
Reference in New Issue
Block a user