Multithreading
ΠΠ½ΠΎΠ³ΠΎΠΏΠΎΡΠΎΡΠ½ΠΎΡΡΡ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ΅Ρ ΠΌΠ°ΠΊΡΠΈΠΌΠ°Π»ΡΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡΠΈ ΡΠΎΠ²ΡΠ΅ΠΌΠ΅Π½Π½ΡΡ ΠΌΠ½ΠΎΠ³ΠΎΡΠ΄Π΅ΡΠ½ΡΡ ΠΏΡΠΎΡΠ΅ΡΡΠΎΡΠΎΠ², Π·Π½Π°ΡΠΈΡΠ΅Π»ΡΠ½ΠΎ ΠΏΠΎΠ²ΡΡΠ°Ρ ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΡ ΠΈΠ³Ρ.
ΠΠ²Π΅Π΄Π΅Π½ΠΈΠ΅ Π² ΠΌΠ½ΠΎΠ³ΠΎΠΏΠΎΡΠΎΡΠ½ΠΎΡΡΡ
Π‘ΠΎΠ²ΡΠ΅ΠΌΠ΅Π½Π½ΡΠ΅ ΠΈΠ³ΡΡ ΡΡΠ΅Π±ΡΡΡ ΡΡΡΠ΅ΠΊΡΠΈΠ²Π½ΠΎΠ³ΠΎ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΡ Π²ΡΠ΅Ρ Π΄ΠΎΡΡΡΠΏΠ½ΡΡ ΡΠ΅ΡΡΡΡΠΎΠ² ΠΏΡΠΎΡΠ΅ΡΡΠΎΡΠ°. Wudgine ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²Π»ΡΠ΅Ρ ΠΌΠΎΡΠ½ΡΡ ΡΠΈΡΡΠ΅ΠΌΡ ΠΌΠ½ΠΎΠ³ΠΎΠΏΠΎΡΠΎΡΠ½ΠΎΡΡΠΈ, ΠΊΠΎΡΠΎΡΠ°Ρ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ΅Ρ ΡΠ°ΡΠΏΠ°ΡΠ°Π»Π»Π΅Π»ΠΈΠ²Π°ΡΡ Π²ΡΡΠΈΡΠ»Π΅Π½ΠΈΡ ΠΈ ΠΎΠΏΡΠΈΠΌΠΈΠ·ΠΈΡΠΎΠ²Π°ΡΡ ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΡ ΠΈΠ³ΡΡ.
Π‘ΠΈΡΡΠ΅ΠΌΠ° Π·Π°Π΄Π°Π½ΠΈΠΉ (Job System)
Π‘ΠΈΡΡΠ΅ΠΌΠ° Π·Π°Π΄Π°Π½ΠΈΠΉ Wudgine β ΡΡΠΎ Π²ΡΡΠΎΠΊΠΎΡΡΠΎΠ²Π½Π΅Π²ΡΠΉ ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡ Π΄Π»Ρ ΡΠ°Π±ΠΎΡΡ Ρ ΠΏΠΎΡΠΎΠΊΠ°ΠΌΠΈ, ΠΊΠΎΡΠΎΡΡΠΉ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ΅Ρ Π»Π΅Π³ΠΊΠΎ ΡΠ°ΡΠΏΠ°ΡΠ°Π»Π»Π΅Π»ΠΈΠ²Π°ΡΡ Π²ΡΡΠΈΡΠ»Π΅Π½ΠΈΡ.
ΠΡΠ½ΠΎΠ²Π½ΡΠ΅ ΠΊΠΎΠ½ΡΠ΅ΠΏΡΠΈΠΈ
- ΠΠ°Π΄Π°Π½ΠΈΠ΅ (Job) β Π°ΡΠΎΠΌΠ°ΡΠ½Π°Ρ Π΅Π΄ΠΈΠ½ΠΈΡΠ° ΡΠ°Π±ΠΎΡΡ, ΠΊΠΎΡΠΎΡΠ°Ρ ΠΌΠΎΠΆΠ΅Ρ Π±ΡΡΡ Π²ΡΠΏΠΎΠ»Π½Π΅Π½Π° ΠΏΠ°ΡΠ°Π»Π»Π΅Π»ΡΠ½ΠΎ
- ΠΡΠ» ΠΏΠΎΡΠΎΠΊΠΎΠ² (Thread Pool) β Π½Π°Π±ΠΎΡ ΡΠ°Π±ΠΎΡΠΈΡ ΠΏΠΎΡΠΎΠΊΠΎΠ² Π΄Π»Ρ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΡ Π·Π°Π΄Π°Π½ΠΈΠΉ
- ΠΠ»Π°Π½ΠΈΡΠΎΠ²ΡΠΈΠΊ (Scheduler) β ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ, ΡΠ°ΡΠΏΡΠ΅Π΄Π΅Π»ΡΡΡΠΈΠΉ Π·Π°Π΄Π°Π½ΠΈΡ ΠΌΠ΅ΠΆΠ΄Ρ ΠΏΠΎΡΠΎΠΊΠ°ΠΌΠΈ
- ΠΠ°Π²ΠΈΡΠΈΠΌΠΎΡΡΠΈ (Dependencies) β ΠΌΠ΅Ρ Π°Π½ΠΈΠ·ΠΌ ΡΠΈΠ½Ρ ΡΠΎΠ½ΠΈΠ·Π°ΡΠΈΠΈ ΠΌΠ΅ΠΆΠ΄Ρ Π·Π°Π΄Π°Π½ΠΈΡΠΌΠΈ
Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΠΈ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ Π·Π°Π΄Π°Π½ΠΈΠΉ
#include "Wudgine/Core/JobSystem.hpp"
// Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ Π·Π°Π΄Π°Π½ΠΈΡ
Wudgine::Core::Job myJob = []() {
// ΠΠΎΠ΄, ΠΊΠΎΡΠΎΡΡΠΉ Π±ΡΠ΄Π΅Ρ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ Π² ΠΎΡΠ΄Π΅Π»ΡΠ½ΠΎΠΌ ΠΏΠΎΡΠΎΠΊΠ΅
for (int i = 0; i < 1000; i++) {
// ΠΡΡΠΈΡΠ»Π΅Π½ΠΈΡ
}
};
// ΠΠ°ΠΏΡΡΠΊ Π·Π°Π΄Π°Π½ΠΈΡ
Wudgine::Core::JobHandle handle = Wudgine::Core::JobSystem::Schedule(myJob);
// ΠΠΆΠΈΠ΄Π°Π½ΠΈΠ΅ Π·Π°Π²Π΅ΡΡΠ΅Π½ΠΈΡ Π·Π°Π΄Π°Π½ΠΈΡ
handle.Wait();
Π Π°Π±ΠΎΡΠ° Ρ Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡΡΠΌΠΈ
// Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΠΏΠ΅ΡΠ²ΠΎΠ³ΠΎ Π·Π°Π΄Π°Π½ΠΈΡ
Wudgine::Core::Job job1 = []() {
// ΠΠ΅ΡΠ²Π°Ρ ΡΠ°ΡΡΡ Π²ΡΡΠΈΡΠ»Π΅Π½ΠΈΠΉ
};
// ΠΠ°ΠΏΡΡΠΊ ΠΏΠ΅ΡΠ²ΠΎΠ³ΠΎ Π·Π°Π΄Π°Π½ΠΈΡ
Wudgine::Core::JobHandle handle1 = Wudgine::Core::JobSystem::Schedule(job1);
// Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ Π²ΡΠΎΡΠΎΠ³ΠΎ Π·Π°Π΄Π°Π½ΠΈΡ, Π·Π°Π²ΠΈΡΡΡΠ΅Π³ΠΎ ΠΎΡ ΠΏΠ΅ΡΠ²ΠΎΠ³ΠΎ
Wudgine::Core::Job job2 = []() {
// ΠΡΠΎΡΠ°Ρ ΡΠ°ΡΡΡ Π²ΡΡΠΈΡΠ»Π΅Π½ΠΈΠΉ, ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΡΡΠ°Ρ ΡΠ΅Π·ΡΠ»ΡΡΠ°ΡΡ ΠΏΠ΅ΡΠ²ΠΎΠΉ
};
// ΠΠ°ΠΏΡΡΠΊ Π²ΡΠΎΡΠΎΠ³ΠΎ Π·Π°Π΄Π°Π½ΠΈΡ Ρ Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡΡΡ ΠΎΡ ΠΏΠ΅ΡΠ²ΠΎΠ³ΠΎ
Wudgine::Core::JobHandle handle2 = Wudgine::Core::JobSystem::Schedule(job2, handle1);
// ΠΠΆΠΈΠ΄Π°Π½ΠΈΠ΅ Π·Π°Π²Π΅ΡΡΠ΅Π½ΠΈΡ Π²ΡΠ΅Ρ
Π·Π°Π΄Π°Π½ΠΈΠΉ
handle2.Wait(); // ΠΠ΅ΡΠ²Π½ΠΎ ΠΎΠΆΠΈΠ΄Π°Π΅Ρ ΡΠ°ΠΊΠΆΠ΅ Π·Π°Π²Π΅ΡΡΠ΅Π½ΠΈΡ handle1
ΠΠ°ΡΠ°Π»Π»Π΅Π»ΡΠ½ΡΠ΅ ΡΠΈΠΊΠ»Ρ
Π‘ΠΈΡΡΠ΅ΠΌΠ° Π·Π°Π΄Π°Π½ΠΈΠΉ Wudgine ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²Π»ΡΠ΅Ρ ΡΠ΄ΠΎΠ±Π½ΡΠ΅ ΠΌΠ΅ΡΠΎΠ΄Ρ Π΄Π»Ρ ΠΏΠ°ΡΠ°Π»Π»Π΅Π»ΡΠ½ΠΎΠ³ΠΎ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΡ ΡΠΈΠΊΠ»ΠΎΠ²:
std::vector<Entity> entities(10000);
// ΠΠ°ΡΠ°Π»Π»Π΅Π»ΡΠ½Π°Ρ ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠ° ΠΌΠ°ΡΡΠΈΠ²Π° ΡΡΡΠ½ΠΎΡΡΠ΅ΠΉ
Wudgine::Core::JobSystem::ParallelFor(0, entities.size(), [&entities](int index) {
// ΠΠ±ΡΠ°Π±ΠΎΡΠΊΠ° ΡΡΡΠ½ΠΎΡΡΠΈ
ProcessEntity(entities[index]);
});
ΠΠ°ΡΠ°Π»Π»Π΅Π»ΡΠ½ΠΎΠ΅ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ ΡΠΈΡΡΠ΅ΠΌ ECS
Wudgine ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ΅Ρ Π²ΡΠΏΠΎΠ»Π½ΡΡΡ ΡΠΈΡΡΠ΅ΠΌΡ ECS ΠΏΠ°ΡΠ°Π»Π»Π΅Π»ΡΠ½ΠΎ, ΡΡΠΎ Π·Π½Π°ΡΠΈΡΠ΅Π»ΡΠ½ΠΎ ΠΏΠΎΠ²ΡΡΠ°Π΅Ρ ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΡ ΠΏΡΠΈ Π±ΠΎΠ»ΡΡΠΎΠΌ ΠΊΠΎΠ»ΠΈΡΠ΅ΡΡΠ²Π΅ ΡΡΡΠ½ΠΎΡΡΠ΅ΠΉ.
ΠΠ°ΡΡΡΠΎΠΉΠΊΠ° ΠΏΠ°ΡΠ°Π»Π»Π΅Π»ΡΠ½ΠΎΠ³ΠΎ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΡ
class MySystem : public Wudgine::ECS::System {
public:
MySystem() {
// Π£ΠΊΠ°Π·ΡΠ²Π°Π΅ΠΌ, ΡΡΠΎ ΡΠΈΡΡΠ΅ΠΌΠ° ΠΌΠΎΠΆΠ΅Ρ Π²ΡΠΏΠΎΠ»Π½ΡΡΡΡΡ ΠΏΠ°ΡΠ°Π»Π»Π΅Π»ΡΠ½ΠΎ
SetParallelExecution(true);
}
void Update(float deltaTime) override {
// ΠΠΎΠ΄ ΡΠΈΡΡΠ΅ΠΌΡ Π±ΡΠ΄Π΅Ρ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΈ ΡΠ°ΡΠΏΠ°ΡΠ°Π»Π»Π΅Π»Π΅Π½
auto view = GetWorld()->GetRegistry().view<ComponentA, ComponentB>();
// ΠΡΠΎΡ ΡΠΈΠΊΠ» Π±ΡΠ΄Π΅Ρ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ ΠΏΠ°ΡΠ°Π»Π»Π΅Π»ΡΠ½ΠΎ
view.each([deltaTime](auto entity, ComponentA& a, ComponentB& b) {
// ΠΠ±ΡΠ°Π±ΠΎΡΠΊΠ° ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½ΡΠΎΠ²
});
}
};
ΠΠ°Π²ΠΈΡΠΈΠΌΠΎΡΡΠΈ ΠΌΠ΅ΠΆΠ΄Ρ ΡΠΈΡΡΠ΅ΠΌΠ°ΠΌΠΈ
ΠΠ»Ρ ΠΊΠΎΡΡΠ΅ΠΊΡΠ½ΠΎΠΉ ΡΠ°Π±ΠΎΡΡ ΠΏΠ°ΡΠ°Π»Π»Π΅Π»ΡΠ½ΡΡ ΡΠΈΡΡΠ΅ΠΌ Π²Π°ΠΆΠ½ΠΎ ΠΏΡΠ°Π²ΠΈΠ»ΡΠ½ΠΎ Π½Π°ΡΡΡΠΎΠΈΡΡ Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡΠΈ ΠΌΠ΅ΠΆΠ΄Ρ Π½ΠΈΠΌΠΈ:
// Π ΠΌΠ΅ΡΠΎΠ΄Π΅ ΠΈΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΠΈ ΠΌΠΈΡΠ° ΠΈΠ»ΠΈ ΡΡΠ΅Π½Ρ
void InitializeSystems() {
auto& world = GetWorld();
// Π‘ΠΎΠ·Π΄Π°Π΅ΠΌ ΡΠΈΡΡΠ΅ΠΌΡ
auto& physicsSystem = world->AddSystem<PhysicsSystem>();
auto& animationSystem = world->AddSystem<AnimationSystem>();
auto& renderSystem = world->AddSystem<RenderSystem>();
// ΠΠ°ΡΡΡΠ°ΠΈΠ²Π°Π΅ΠΌ Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡΠΈ
// AnimationSystem Π±ΡΠ΄Π΅Ρ Π²ΡΠΏΠΎΠ»Π½ΡΡΡΡΡ ΡΠΎΠ»ΡΠΊΠΎ ΠΏΠΎΡΠ»Π΅ PhysicsSystem
animationSystem.AddDependency(physicsSystem);
// RenderSystem Π±ΡΠ΄Π΅Ρ Π²ΡΠΏΠΎΠ»Π½ΡΡΡΡΡ ΡΠΎΠ»ΡΠΊΠΎ ΠΏΠΎΡΠ»Π΅ AnimationSystem
renderSystem.AddDependency(animationSystem);
}
ΠΡΠΈΠ½Ρ ΡΠΎΠ½Π½Π°Ρ Π·Π°Π³ΡΡΠ·ΠΊΠ° ΡΠ΅ΡΡΡΡΠΎΠ²
Wudgine ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²Π»ΡΠ΅Ρ ΠΌΠ΅Ρ Π°Π½ΠΈΠ·ΠΌΡ Π΄Π»Ρ Π°ΡΠΈΠ½Ρ ΡΠΎΠ½Π½ΠΎΠΉ Π·Π°Π³ΡΡΠ·ΠΊΠΈ ΡΠ΅ΡΡΡΡΠΎΠ², ΡΡΠΎ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ΅Ρ ΠΈΠ·Π±Π΅ΠΆΠ°ΡΡ Π·Π°Π΄Π΅ΡΠΆΠ΅ΠΊ Π²ΠΎ Π²ΡΠ΅ΠΌΡ ΠΈΠ³ΡΠΎΠ²ΠΎΠ³ΠΎ ΠΏΡΠΎΡΠ΅ΡΡΠ°.
ΠΠ°Π³ΡΡΠ·ΠΊΠ° ΡΠ΅ΠΊΡΡΡΡ
// ΠΡΠΈΠ½Ρ
ΡΠΎΠ½Π½Π°Ρ Π·Π°Π³ΡΡΠ·ΠΊΠ° ΡΠ΅ΠΊΡΡΡΡΡ
Wudgine::Resources::TextureHandle textureHandle =
Wudgine::Resources::ResourceManager::LoadTextureAsync("textures/character.png");
// ΠΡΠΎΠ²Π΅ΡΠΊΠ° Π³ΠΎΡΠΎΠ²Π½ΠΎΡΡΠΈ ΡΠ΅ΡΡΡΡΠ°
if (textureHandle.IsReady()) {
// ΠΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅ ΡΠ΅ΠΊΡΡΡΡΡ
auto& texture = textureHandle.Get();
// ...
} else {
// ΠΡΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΠ΅ Π·Π°Π³Π»ΡΡΠΊΠΈ ΠΈΠ»ΠΈ ΠΈΠ½Π΄ΠΈΠΊΠ°ΡΠΎΡΠ° Π·Π°Π³ΡΡΠ·ΠΊΠΈ
}
ΠΠ°Π³ΡΡΠ·ΠΊΠ° ΠΌΠΎΠ΄Π΅Π»Π΅ΠΉ
// ΠΡΠΈΠ½Ρ
ΡΠΎΠ½Π½Π°Ρ Π·Π°Π³ΡΡΠ·ΠΊΠ° ΠΌΠΎΠ΄Π΅Π»ΠΈ
Wudgine::Resources::ModelHandle modelHandle =
Wudgine::Resources::ResourceManager::LoadModelAsync("models/character.fbx");
// Π£ΡΡΠ°Π½ΠΎΠ²ΠΊΠ° callback-ΡΡΠ½ΠΊΡΠΈΠΈ, ΠΊΠΎΡΠΎΡΠ°Ρ Π±ΡΠ΄Π΅Ρ Π²ΡΠ·Π²Π°Π½Π° ΠΏΠΎΡΠ»Π΅ Π·Π°Π³ΡΡΠ·ΠΊΠΈ
modelHandle.SetOnLoadedCallback([](const Wudgine::Resources::Model& model) {
// ΠΠΎΠ΄, Π²ΡΠΏΠΎΠ»Π½ΡΠ΅ΠΌΡΠΉ ΠΏΠΎΡΠ»Π΅ Π·Π°Π³ΡΡΠ·ΠΊΠΈ ΠΌΠΎΠ΄Π΅Π»ΠΈ
std::cout << "Model loaded with " << model.GetMeshCount() << " meshes" << std::endl;
});
ΠΠΎΡΠΎΠΊΠΎΠ±Π΅Π·ΠΎΠΏΠ°ΡΠ½ΡΠ΅ ΡΡΡΡΠΊΡΡΡΡ Π΄Π°Π½Π½ΡΡ
Wudgine ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²Π»ΡΠ΅Ρ Π½Π°Π±ΠΎΡ ΠΏΠΎΡΠΎΠΊΠΎΠ±Π΅Π·ΠΎΠΏΠ°ΡΠ½ΡΡ ΡΡΡΡΠΊΡΡΡ Π΄Π°Π½Π½ΡΡ Π΄Π»Ρ Π±Π΅Π·ΠΎΠΏΠ°ΡΠ½ΠΎΠ³ΠΎ ΠΎΠ±ΠΌΠ΅Π½Π° ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΠ΅ΠΉ ΠΌΠ΅ΠΆΠ΄Ρ ΠΏΠΎΡΠΎΠΊΠ°ΠΌΠΈ.
ΠΡΠΎΠΌΠ°ΡΠ½ΡΠ΅ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΠΈ
#include "Wudgine/Core/Atomic.hpp"
// ΠΡΠΎΠΌΠ°ΡΠ½ΡΠΉ ΡΡΠ΅ΡΡΠΈΠΊ
Wudgine::Core::AtomicInt counter(0);
// ΠΠ½ΠΊΡΠ΅ΠΌΠ΅Π½Ρ ΡΡΠ΅ΡΡΠΈΠΊΠ° ΠΈΠ· ΡΠ°Π·Π½ΡΡ
ΠΏΠΎΡΠΎΠΊΠΎΠ²
counter.Increment();
// ΠΠΎΠ»ΡΡΠ΅Π½ΠΈΠ΅ Π·Π½Π°ΡΠ΅Π½ΠΈΡ
int value = counter.Get();
ΠΠΎΡΠΎΠΊΠΎΠ±Π΅Π·ΠΎΠΏΠ°ΡΠ½Π°Ρ ΠΎΡΠ΅ΡΠ΅Π΄Ρ
#include "Wudgine/Core/ConcurrentQueue.hpp"
// Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΠΏΠΎΡΠΎΠΊΠΎΠ±Π΅Π·ΠΎΠΏΠ°ΡΠ½ΠΎΠΉ ΠΎΡΠ΅ΡΠ΅Π΄ΠΈ
Wudgine::Core::ConcurrentQueue<int> queue;
// ΠΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ ΡΠ»Π΅ΠΌΠ΅Π½ΡΠΎΠ² (ΠΌΠΎΠΆΠ΅Ρ Π²ΡΠ·ΡΠ²Π°ΡΡΡΡ ΠΈΠ· Π»ΡΠ±ΠΎΠ³ΠΎ ΠΏΠΎΡΠΎΠΊΠ°)
queue.Push(42);
// ΠΠ·Π²Π»Π΅ΡΠ΅Π½ΠΈΠ΅ ΡΠ»Π΅ΠΌΠ΅Π½ΡΠΎΠ² (ΠΌΠΎΠΆΠ΅Ρ Π²ΡΠ·ΡΠ²Π°ΡΡΡΡ ΠΈΠ· Π»ΡΠ±ΠΎΠ³ΠΎ ΠΏΠΎΡΠΎΠΊΠ°)
int value;
if (queue.TryPop(value)) {
// Π£ΡΠΏΠ΅ΡΠ½ΠΎ ΠΈΠ·Π²Π»Π΅ΡΠ΅Π½ ΡΠ»Π΅ΠΌΠ΅Π½Ρ
std::cout << "Popped value: " << value << std::endl;
}
ΠΠ»ΠΎΠΊΠΈΡΠΎΠ²ΠΊΠΈ ΠΈ ΡΠΈΠ½Ρ ΡΠΎΠ½ΠΈΠ·Π°ΡΠΈΡ
Wudgine ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²Π»ΡΠ΅Ρ ΡΠ°Π·Π»ΠΈΡΠ½ΡΠ΅ ΠΏΡΠΈΠΌΠΈΡΠΈΠ²Ρ ΡΠΈΠ½Ρ ΡΠΎΠ½ΠΈΠ·Π°ΡΠΈΠΈ Π΄Π»Ρ Π±Π΅Π·ΠΎΠΏΠ°ΡΠ½ΠΎΠ³ΠΎ Π΄ΠΎΡΡΡΠΏΠ° ΠΊ ΡΠ°Π·Π΄Π΅Π»ΡΠ΅ΠΌΡΠΌ ΡΠ΅ΡΡΡΡΠ°ΠΌ.
ΠΡΡΡΠ΅ΠΊΡΡ
#include "Wudgine/Core/Mutex.hpp"
// Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΠΌΡΡΡΠ΅ΠΊΡΠ°
Wudgine::Core::Mutex mutex;
// ΠΠ°ΡΠΈΡΠ° ΠΊΡΠΈΡΠΈΡΠ΅ΡΠΊΠΎΠΉ ΡΠ΅ΠΊΡΠΈΠΈ
{
Wudgine::Core::MutexLock lock(mutex);
// ΠΠΎΠ΄, ΡΡΠ΅Π±ΡΡΡΠΈΠΉ ΡΠΊΡΠΊΠ»ΡΠ·ΠΈΠ²Π½ΠΎΠ³ΠΎ Π΄ΠΎΡΡΡΠΏΠ°
}
Π£ΡΠ»ΠΎΠ²Π½ΡΠ΅ ΠΏΠ΅ΡΠ΅ΠΌΠ΅Π½Π½ΡΠ΅
#include "Wudgine/Core/ConditionVariable.hpp"
Wudgine::Core::Mutex mutex;
Wudgine::Core::ConditionVariable cv;
bool dataReady = false;
// ΠΠΎΡΠΎΠΊ-ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»Ρ
void Producer() {
// ΠΠΎΠ΄Π³ΠΎΡΠΎΠ²ΠΊΠ° Π΄Π°Π½Π½ΡΡ
{
Wudgine::Core::MutexLock lock(mutex);
dataReady = true;
}
// Π£Π²Π΅Π΄ΠΎΠΌΠ»Π΅Π½ΠΈΠ΅ ΠΏΠΎΡΡΠ΅Π±ΠΈΡΠ΅Π»Ρ
cv.NotifyOne();
}
// ΠΠΎΡΠΎΠΊ-ΠΏΠΎΡΡΠ΅Π±ΠΈΡΠ΅Π»Ρ
void Consumer() {
Wudgine::Core::MutexLock lock(mutex);
// ΠΠΆΠΈΠ΄Π°Π½ΠΈΠ΅ Π³ΠΎΡΠΎΠ²Π½ΠΎΡΡΠΈ Π΄Π°Π½Π½ΡΡ
cv.Wait(lock, []{ return dataReady; });
// ΠΠ±ΡΠ°Π±ΠΎΡΠΊΠ° Π΄Π°Π½Π½ΡΡ
}
ΠΡΡΡΠΈΠ΅ ΠΏΡΠ°ΠΊΡΠΈΠΊΠΈ ΠΌΠ½ΠΎΠ³ΠΎΠΏΠΎΡΠΎΡΠ½ΠΎΠ³ΠΎ ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΌΠΈΡΠΎΠ²Π°Π½ΠΈΡ
ΠΠ·Π±Π΅Π³Π°ΠΉΡΠ΅ Π³ΠΎΠ½ΠΎΠΊ Π΄Π°Π½Π½ΡΡ
- ΠΡΠΏΠΎΠ»ΡΠ·ΡΠΉΡΠ΅ ΠΌΡΡΡΠ΅ΠΊΡΡ ΠΈΠ»ΠΈ Π°ΡΠΎΠΌΠ°ΡΠ½ΡΠ΅ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΠΈ Π΄Π»Ρ Π·Π°ΡΠΈΡΡ ΡΠ°Π·Π΄Π΅Π»ΡΠ΅ΠΌΡΡ Π΄Π°Π½Π½ΡΡ
- ΠΠΈΠ½ΠΈΠΌΠΈΠ·ΠΈΡΡΠΉΡΠ΅ Π²ΡΠ΅ΠΌΡ Π±Π»ΠΎΠΊΠΈΡΠΎΠ²ΠΊΠΈ ΠΌΡΡΡΠ΅ΠΊΡΠΎΠ²
- ΠΠΎ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡΠΈ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠΉΡΠ΅ Π»ΠΎΠΊΠ°Π»ΡΠ½ΡΠ΅ ΠΊΠΎΠΏΠΈΠΈ Π΄Π°Π½Π½ΡΡ
ΠΠΈΠ½ΠΈΠΌΠΈΠ·ΠΈΡΡΠΉΡΠ΅ Π±Π»ΠΎΠΊΠΈΡΠΎΠ²ΠΊΠΈ
- ΠΡΠΏΠΎΠ»ΡΠ·ΡΠΉΡΠ΅ lock-free Π°Π»Π³ΠΎΡΠΈΡΠΌΡ, Π³Π΄Π΅ ΡΡΠΎ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ
- Π Π°Π·Π΄Π΅Π»ΡΠΉΡΠ΅ Π΄Π°Π½Π½ΡΠ΅ Π½Π° Π½Π΅Π·Π°Π²ΠΈΡΠΈΠΌΡΠ΅ ΡΠ°ΡΡΠΈ Π΄Π»Ρ ΠΏΠ°ΡΠ°Π»Π»Π΅Π»ΡΠ½ΠΎΠΉ ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠΈ
- ΠΡΠΏΠΎΠ»ΡΠ·ΡΠΉΡΠ΅ fine-grained locking Π²ΠΌΠ΅ΡΡΠΎ Π³Π»ΠΎΠ±Π°Π»ΡΠ½ΡΡ Π±Π»ΠΎΠΊΠΈΡΠΎΠ²ΠΎΠΊ
ΠΠΏΡΠΈΠΌΠΈΠ·ΠΈΡΡΠΉΡΠ΅ ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΡ
- Π£ΡΠΈΡΡΠ²Π°ΠΉΡΠ΅ ΠΊΡΡ-Π»ΠΈΠ½ΠΈΠΈ ΠΏΡΠΎΡΠ΅ΡΡΠΎΡΠ° ΠΏΡΠΈ ΠΏΡΠΎΠ΅ΠΊΡΠΈΡΠΎΠ²Π°Π½ΠΈΠΈ ΡΡΡΡΠΊΡΡΡ Π΄Π°Π½Π½ΡΡ
- ΠΡΠΏΠΎΠ»ΡΠ·ΡΠΉΡΠ΅ ΠΏΠ°ΠΊΠ΅ΡΠ½ΡΡ ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΡ Π΄Π»Ρ ΠΌΠΈΠ½ΠΈΠΌΠΈΠ·Π°ΡΠΈΠΈ Π½Π°ΠΊΠ»Π°Π΄Π½ΡΡ ΡΠ°ΡΡ ΠΎΠ΄ΠΎΠ²
- ΠΠ°Π»Π°Π½ΡΠΈΡΡΠΉΡΠ΅ Π½Π°Π³ΡΡΠ·ΠΊΡ ΠΌΠ΅ΠΆΠ΄Ρ ΠΏΠΎΡΠΎΠΊΠ°ΠΌΠΈ
ΠΡΠ»Π°Π΄ΠΊΠ° ΠΌΠ½ΠΎΠ³ΠΎΠΏΠΎΡΠΎΡΠ½ΠΎΠ³ΠΎ ΠΊΠΎΠ΄Π°
Wudgine ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²Π»ΡΠ΅Ρ ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½ΡΡ Π΄Π»Ρ ΠΎΡΠ»Π°Π΄ΠΊΠΈ ΠΌΠ½ΠΎΠ³ΠΎΠΏΠΎΡΠΎΡΠ½ΠΎΠ³ΠΎ ΠΊΠΎΠ΄Π°:
- ΠΡΠΎΡΠΈΠ»ΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ ΠΏΠΎΡΠΎΠΊΠΎΠ² β Π°Π½Π°Π»ΠΈΠ· Π²ΡΠ΅ΠΌΠ΅Π½ΠΈ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΡ Π·Π°Π΄Π°Π½ΠΈΠΉ Π² ΡΠ°Π·Π½ΡΡ ΠΏΠΎΡΠΎΠΊΠ°Ρ
- ΠΠΈΠ·ΡΠ°Π»ΠΈΠ·Π°ΡΠΈΡ Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡΠ΅ΠΉ β Π³ΡΠ°ΡΠΈΡΠ΅ΡΠΊΠΎΠ΅ ΠΏΡΠ΅Π΄ΡΡΠ°Π²Π»Π΅Π½ΠΈΠ΅ Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡΠ΅ΠΉ ΠΌΠ΅ΠΆΠ΄Ρ Π·Π°Π΄Π°Π½ΠΈΡΠΌΠΈ
- ΠΠ΅ΡΠ΅ΠΊΡΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ Π³ΠΎΠ½ΠΎΠΊ Π΄Π°Π½Π½ΡΡ β ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½ΡΡ Π΄Π»Ρ Π²ΡΡΠ²Π»Π΅Π½ΠΈΡ ΠΏΠΎΡΠ΅Π½ΡΠΈΠ°Π»ΡΠ½ΡΡ ΠΏΡΠΎΠ±Π»Π΅ΠΌ ΡΠΈΠ½Ρ ΡΠΎΠ½ΠΈΠ·Π°ΡΠΈΠΈ
ΠΡΠΈΠΌΠ΅ΡΡ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΡ
ΠΠ°ΡΠ°Π»Π»Π΅Π»ΡΠ½Π°Ρ ΡΠΈΠ·ΠΈΡΠ΅ΡΠΊΠ°Ρ ΡΠΈΠΌΡΠ»ΡΡΠΈΡ
class ParallelPhysicsSystem : public Wudgine::ECS::System {
public:
ParallelPhysicsSystem() {
SetParallelExecution(true);
}
void Update(float deltaTime) override {
auto view = GetWorld()->GetRegistry().view<RigidBodyComponent, TransformComponent>();
// Π Π°Π·Π΄Π΅Π»Π΅Π½ΠΈΠ΅ ΠΏΡΠΎΡΡΡΠ°Π½ΡΡΠ²Π° Π½Π° ΡΠ΅ΡΠΊΡ Π΄Π»Ρ ΠΏΠ°ΡΠ°Π»Π»Π΅Π»ΡΠ½ΠΎΠΉ ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠΈ
std::vector<std::vector<Entity>> spatialGrid = DivideSpatialGrid(view);
// Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ Π·Π°Π΄Π°Π½ΠΈΠΉ Π΄Π»Ρ ΠΊΠ°ΠΆΠ΄ΠΎΠΉ ΡΡΠ΅ΠΉΠΊΠΈ ΡΠ΅ΡΠΊΠΈ
std::vector<Wudgine::Core::JobHandle> handles;
for (auto& cell : spatialGrid) {
auto handle = Wudgine::Core::JobSystem::Schedule([this, &cell, deltaTime]() {
// ΠΠ±ΡΠ°Π±ΠΎΡΠΊΠ° ΡΠΈΠ·ΠΈΠΊΠΈ Π΄Π»Ρ ΡΡΡΠ½ΠΎΡΡΠ΅ΠΉ Π² ΡΡΠ΅ΠΉΠΊΠ΅
for (auto entity : cell) {
UpdatePhysics(entity, deltaTime);
}
});
handles.push_back(handle);
}
// ΠΠΆΠΈΠ΄Π°Π½ΠΈΠ΅ Π·Π°Π²Π΅ΡΡΠ΅Π½ΠΈΡ Π²ΡΠ΅Ρ
Π·Π°Π΄Π°Π½ΠΈΠΉ
for (auto& handle : handles) {
handle.Wait();
}
// Π Π°Π·ΡΠ΅ΡΠ΅Π½ΠΈΠ΅ ΠΊΠΎΠ»Π»ΠΈΠ·ΠΈΠΉ ΠΌΠ΅ΠΆΠ΄Ρ ΡΡΠ΅ΠΉΠΊΠ°ΠΌΠΈ
ResolveInterCellCollisions(spatialGrid);
}
private:
// ΠΡΠΏΠΎΠΌΠΎΠ³Π°ΡΠ΅Π»ΡΠ½ΡΠ΅ ΠΌΠ΅ΡΠΎΠ΄Ρ
};
ΠΡΠΈΠ½Ρ ΡΠΎΠ½Π½Π°Ρ Π³Π΅Π½Π΅ΡΠ°ΡΠΈΡ ΠΏΡΠΎΡΠ΅Π΄ΡΡΠ½ΠΎΠ³ΠΎ ΠΊΠΎΠ½ΡΠ΅Π½ΡΠ°
class ProceduralTerrainGenerator {
public:
void GenerateTerrainAsync(int width, int height, float scale) {
// Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ Π·Π°Π΄Π°Π½ΠΈΡ Π΄Π»Ρ Π³Π΅Π½Π΅ΡΠ°ΡΠΈΠΈ ΠΊΠ°ΡΡΡ Π²ΡΡΠΎΡ
auto heightmapJob = Wudgine::Core::JobSystem::Schedule([this, width, height, scale]() {
m_HeightMap = GenerateHeightMap(width, height, scale);
});
// Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ Π·Π°Π΄Π°Π½ΠΈΡ Π΄Π»Ρ Π³Π΅Π½Π΅ΡΠ°ΡΠΈΠΈ ΡΠ΅ΠΊΡΡΡΡ, Π·Π°Π²ΠΈΡΡΡΠ΅Π³ΠΎ ΠΎΡ ΠΊΠ°ΡΡΡ Π²ΡΡΠΎΡ
auto textureJob = Wudgine::Core::JobSystem::Schedule([this]() {
m_DiffuseMap = GenerateDiffuseMap(m_HeightMap);
m_NormalMap = GenerateNormalMap(m_HeightMap);
}, heightmapJob);
// Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ Π·Π°Π΄Π°Π½ΠΈΡ Π΄Π»Ρ Π³Π΅Π½Π΅ΡΠ°ΡΠΈΠΈ ΠΌΠ΅ΡΠ°, Π·Π°Π²ΠΈΡΡΡΠ΅Π³ΠΎ ΠΎΡ ΠΊΠ°ΡΡΡ Π²ΡΡΠΎΡ
auto meshJob = Wudgine::Core::JobSystem::Schedule([this]() {
m_Mesh = GenerateMesh(m_HeightMap);
}, heightmapJob);
// Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ Π·Π°Π΄Π°Π½ΠΈΡ Π΄Π»Ρ ΡΠΈΠ½Π°Π»ΡΠ½ΠΎΠΉ ΡΠ±ΠΎΡΠΊΠΈ, Π·Π°Π²ΠΈΡΡΡΠ΅Π³ΠΎ ΠΎΡ ΡΠ΅ΠΊΡΡΡΡ ΠΈ ΠΌΠ΅ΡΠ°
m_FinalHandle = Wudgine::Core::JobSystem::Schedule([this]() {
m_Terrain = CreateTerrain(m_Mesh, m_DiffuseMap, m_NormalMap);
m_IsReady = true;
if (m_OnCompletedCallback) {
m_OnCompletedCallback(m_Terrain);
}
}, Wudgine::Core::JobHandle::CombineDependencies(textureJob, meshJob));
}
bool IsReady() const { return m_IsReady; }
void SetOnCompletedCallback(std::function<void(const Terrain&)> callback) {
m_OnCompletedCallback = std::move(callback);
}
private:
// ΠΠ°Π½Π½ΡΠ΅ ΠΈ Π²ΡΠΏΠΎΠΌΠΎΠ³Π°ΡΠ΅Π»ΡΠ½ΡΠ΅ ΠΌΠ΅ΡΠΎΠ΄Ρ
HeightMap m_HeightMap;
Texture m_DiffuseMap;
Texture m_NormalMap;
Mesh m_Mesh;
Terrain m_Terrain;
bool m_IsReady = false;
Wudgine::Core::JobHandle m_FinalHandle;
std::function<void(const Terrain&)> m_OnCompletedCallback;
};
Π§ΡΠΎ Π΄Π°Π»ΡΡΠ΅?
- ΠΠ·ΡΡΠΈΡΠ΅ ΠΎΠΏΡΠΈΠΌΠΈΠ·Π°ΡΠΈΡ ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΠΈ Π΄Π»Ρ Π΄Π°Π»ΡΠ½Π΅ΠΉΡΠ΅Π³ΠΎ ΡΠ»ΡΡΡΠ΅Π½ΠΈΡ Π±ΡΡΡΡΠΎΠ΄Π΅ΠΉΡΡΠ²ΠΈΡ Π²Π°ΡΠ΅ΠΉ ΠΈΠ³ΡΡ
- ΠΠ·Π½Π°ΠΊΠΎΠΌΡΡΠ΅ΡΡ Ρ ΡΠ΅ΡΠ΅Π²ΡΠΌ Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡΠ²ΠΈΠ΅ΠΌ Π΄Π»Ρ ΡΠΎΠ·Π΄Π°Π½ΠΈΡ ΠΌΠ½ΠΎΠ³ΠΎΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»ΡΡΠΊΠΈΡ ΠΈΠ³Ρ
- ΠΡΡΠ»Π΅Π΄ΡΠΉΡΠ΅ ΡΠ°ΡΡΠΈΡΠ΅Π½Π½ΡΡ ΡΠ°Π±ΠΎΡΡ Ρ ΡΠ΅ΡΡΡΡΠ°ΠΌΠΈ Π΄Π»Ρ ΠΎΠΏΡΠΈΠΌΠΈΠ·Π°ΡΠΈΠΈ Π·Π°Π³ΡΡΠ·ΠΊΠΈ ΠΈ ΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΡ ΠΈΠ³ΡΠΎΠ²ΡΠΌΠΈ ΡΠ΅ΡΡΡΡΠ°ΠΌΠΈ
ΠΠ½ΠΎΠ³ΠΎΠΏΠΎΡΠΎΡΠ½ΠΎΠ΅ ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΌΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ ΠΌΠΎΠΆΠ΅Ρ Π±ΡΡΡ ΡΠ»ΠΎΠΆΠ½ΡΠΌ ΠΈ ΠΏΠΎΠ΄Π²Π΅ΡΠΆΠ΅Π½Π½ΡΠΌ ΠΎΡΠΈΠ±ΠΊΠ°ΠΌ. ΠΡΠ΅Π³Π΄Π° ΡΡΠ°ΡΠ΅Π»ΡΠ½ΠΎ ΡΠ΅ΡΡΠΈΡΡΠΉΡΠ΅ Π²Π°Ρ ΠΊΠΎΠ΄ ΠΈ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠΉΡΠ΅ ΠΈΠ½ΡΡΡΡΠΌΠ΅Π½ΡΡ ΠΏΡΠΎΡΠΈΠ»ΠΈΡΠΎΠ²Π°Π½ΠΈΡ Π΄Π»Ρ Π²ΡΡΠ²Π»Π΅Π½ΠΈΡ ΠΏΡΠΎΠ±Π»Π΅ΠΌ ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΠΈ ΠΈ ΡΠΈΠ½Ρ ΡΠΎΠ½ΠΈΠ·Π°ΡΠΈΠΈ.