feat: improved task counting thread safety
This commit is contained in:
parent
df31dea9c7
commit
32a9fc24e5
|
|
@ -17,7 +17,7 @@
|
||||||
#define likely(cond_) (cond_)
|
#define likely(cond_) (cond_)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define SIM_MULTITHREADING 0
|
#define SIM_MULTITHREADING 1
|
||||||
|
|
||||||
namespace simulation {
|
namespace simulation {
|
||||||
bool drawDebugInfo{ true };
|
bool drawDebugInfo{ true };
|
||||||
|
|
@ -35,6 +35,7 @@ static std::vector<std::shared_ptr<ThreadWorkload>> underpopulated{};
|
||||||
static std::vector<std::shared_ptr<ThreadWorkload>> born{};
|
static std::vector<std::shared_ptr<ThreadWorkload>> born{};
|
||||||
static uint64_t generationStartTime{ 0 };
|
static uint64_t generationStartTime{ 0 };
|
||||||
static unsigned tasks{ 0 }; std::mutex tasksMutex{};
|
static unsigned tasks{ 0 }; std::mutex tasksMutex{};
|
||||||
|
static std::condition_variable tasksChanged{};
|
||||||
|
|
||||||
CellIterator::CellIterator(Cell begin, Cell end)
|
CellIterator::CellIterator(Cell begin, Cell end)
|
||||||
: state{ begin } , begin{ begin }, end{ end } {}
|
: state{ begin } , begin{ begin }, end{ end } {}
|
||||||
|
|
@ -77,14 +78,28 @@ static size_t CountNeighbors(Cell const &cell) {
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void BlockUntilTasksDone() {
|
||||||
|
std::unique_lock lock{ tasksMutex };
|
||||||
|
while (tasks > 0) {
|
||||||
|
tasksChanged.wait(lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void TaskBegin() {
|
||||||
|
std::scoped_lock lock{ tasksMutex };
|
||||||
|
tasks++;
|
||||||
|
}
|
||||||
|
|
||||||
static void TaskComplete() {
|
static void TaskComplete() {
|
||||||
std::scoped_lock lock{ tasksMutex };
|
std::scoped_lock lock{ tasksMutex };
|
||||||
if (--tasks == 0) {
|
if (--tasks == 0) {
|
||||||
SDL_Log("Generation Complete %lfs", (double)(SDL_GetTicksNS() - generationStartTime) * 0.0000000001);
|
SDL_Log("Generation Complete %lfs", (double)(SDL_GetTicksNS() - generationStartTime) * 0.0000000001);
|
||||||
}
|
}
|
||||||
|
tasksChanged.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void FindOverpopulated(std::shared_ptr<ThreadWorkload> wl) {
|
static void FindOverpopulated(std::shared_ptr<ThreadWorkload> wl) {
|
||||||
|
TaskBegin();
|
||||||
std::scoped_lock lock{ wl->mtx };
|
std::scoped_lock lock{ wl->mtx };
|
||||||
wl->changes.clear();
|
wl->changes.clear();
|
||||||
|
|
||||||
|
|
@ -102,6 +117,7 @@ static void FindOverpopulated(std::shared_ptr<ThreadWorkload> wl) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void FindUnderpopulated(std::shared_ptr<ThreadWorkload> wl) {
|
static void FindUnderpopulated(std::shared_ptr<ThreadWorkload> wl) {
|
||||||
|
TaskBegin();
|
||||||
std::scoped_lock lock{ wl->mtx };
|
std::scoped_lock lock{ wl->mtx };
|
||||||
wl->changes.clear();
|
wl->changes.clear();
|
||||||
|
|
||||||
|
|
@ -119,6 +135,7 @@ static void FindUnderpopulated(std::shared_ptr<ThreadWorkload> wl) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void FindBorn(std::shared_ptr<ThreadWorkload> wl) {
|
static void FindBorn(std::shared_ptr<ThreadWorkload> wl) {
|
||||||
|
TaskBegin();
|
||||||
std::scoped_lock lock{ wl->mtx };
|
std::scoped_lock lock{ wl->mtx };
|
||||||
wl->changes.clear();
|
wl->changes.clear();
|
||||||
|
|
||||||
|
|
@ -139,6 +156,7 @@ static void FindBorn(std::shared_ptr<ThreadWorkload> wl) {
|
||||||
static void PopulateChanges() {
|
static void PopulateChanges() {
|
||||||
static bool first_run{ true };
|
static bool first_run{ true };
|
||||||
#if SIM_MULTITHREADING
|
#if SIM_MULTITHREADING
|
||||||
|
BlockUntilTasksDone();
|
||||||
constexpr size_t split{ 4 };
|
constexpr size_t split{ 4 };
|
||||||
if (first_run) {
|
if (first_run) {
|
||||||
first_run = false;
|
first_run = false;
|
||||||
|
|
@ -148,8 +166,6 @@ static void PopulateChanges() {
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_Log("Multithreading ON");
|
SDL_Log("Multithreading ON");
|
||||||
{ std::scoped_lock lock{ tasksMutex };
|
|
||||||
tasks = 3 * split; }
|
|
||||||
generationStartTime = SDL_GetTicksNS();
|
generationStartTime = SDL_GetTicksNS();
|
||||||
size_t const seg_length{ living.size() / split };
|
size_t const seg_length{ living.size() / split };
|
||||||
for (size_t i{ 0 }; i < split; ++i) {
|
for (size_t i{ 0 }; i < split; ++i) {
|
||||||
|
|
@ -196,6 +212,7 @@ static void PopulateChanges() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitializeRandom(size_t livingChance, int64_t fillArea) {
|
void InitializeRandom(size_t livingChance, int64_t fillArea) {
|
||||||
|
BlockUntilTasksDone();
|
||||||
living.clear();
|
living.clear();
|
||||||
|
|
||||||
Cell itr{ 0, 0 };
|
Cell itr{ 0, 0 };
|
||||||
|
|
@ -213,6 +230,7 @@ void InitializeRandom(size_t livingChance, int64_t fillArea) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Step() {
|
void Step() {
|
||||||
|
BlockUntilTasksDone();
|
||||||
for (std::shared_ptr<ThreadWorkload> wl : underpopulated) {
|
for (std::shared_ptr<ThreadWorkload> wl : underpopulated) {
|
||||||
if (wl == nullptr) continue;
|
if (wl == nullptr) continue;
|
||||||
std::scoped_lock l{ wl->mtx };
|
std::scoped_lock l{ wl->mtx };
|
||||||
|
|
@ -258,6 +276,7 @@ void Draw(SDL_Renderer *renderer, double cellSizePercent) {
|
||||||
if (!drawDebugInfo) {
|
if (!drawDebugInfo) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
BlockUntilTasksDone();
|
||||||
for (std::shared_ptr<ThreadWorkload> wl : overpopulated) {
|
for (std::shared_ptr<ThreadWorkload> wl : overpopulated) {
|
||||||
std::scoped_lock l{ wl->mtx };
|
std::scoped_lock l{ wl->mtx };
|
||||||
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
|
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue