Skip to content

Commit

Permalink
refactor: replace manual threads with parallel for_each
Browse files Browse the repository at this point in the history
After reading about thread pools in "C++ Concurrency in Action", the
previous approach was rudimentary and very likely buggy. It should
be easier and safer to rely on the standard algorithms.

The CMAKE_OSX_DEPLOYMENT_TARGET became necessary with
the inclusion of experimental-library, otherwise the following
warning appeared:

    ld: warning: object file (/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/lib/libc++experimental.a[arm64][3](libdispatch.cpp.o)) was built for newer 'macOS' version (15.2) than being linked (15.0)
  • Loading branch information
andreaswachowski committed Feb 2, 2025
1 parent d26604e commit 74fe8ab
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 30 deletions.
12 changes: 12 additions & 0 deletions cmake/Config.cmake
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_OSX_DEPLOYMENT_TARGET 15.2)

# Export compile commands for tools like clang-tidy
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

# Parallel algorithms support for Clang 17+ and operating systems with libc++
# Primary source:
# https://libcxx.llvm.org/UserDocumentation.html#enabling-experimental-c-library-features
# Found via https://github.com/Stellarium/stellarium/pull/3902/files via
# https://github.com/Stellarium/stellarium/pull/3902 via
# https://github.com/llvm/llvm-project/issues/57898
if((${CMAKE_CXX_COMPILER_VERSION} VERSION_GREATER 16.0)
AND (APPLE OR ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD"))
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexperimental-library")
endif()
35 changes: 5 additions & 30 deletions src/main.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#include <ncurses.h>
#include <chrono>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <execution>
#include <iostream>
#include <random>
#include <thread>
Expand All @@ -15,33 +15,10 @@
#include "spdlog/spdlog.h"

namespace {
void update_boid_chunk(std::vector<Boid>& boids, size_t start, size_t end) {
for (size_t i = start; i < end; ++i) {
boids[i].update();
}
}

void update_boids(std::vector<Boid>& boids, unsigned int num_threads) {
void update_boids(std::vector<Boid>& boids) {

Check warning on line 18 in src/main.cpp

View workflow job for this annotation

GitHub Actions / cpp-linter

src/main.cpp:18:38 [misc-unused-parameters]

parameter 'boids' is unused
size_t total = boids.size();

Check warning on line 19 in src/main.cpp

View workflow job for this annotation

GitHub Actions / cpp-linter

src/main.cpp:19:10 [cppcoreguidelines-init-variables]

variable 'total' is not initialized
auto chunk_size = static_cast<size_t>(
std::ceil(static_cast<float>(total) / static_cast<float>(num_threads)));

std::vector<std::thread> threads;

for (int i = 0; i < num_threads; ++i) {
size_t start = i * chunk_size;
size_t end = std::min(start + chunk_size, total);

if (start < total) { // Avoid launching empty threads
spdlog::debug("Thread {}: Boids {} to {}", i, i * chunk_size,
(i * chunk_size) + chunk_size);
threads.emplace_back(update_boid_chunk, std::ref(boids), start, end);
}
}

for (auto& thread : threads) {
thread.join();
}
std::for_each(std::execution::par, boids.begin(), boids.end(),
[](Boid& boid) { boid.update(); });
}
} // namespace

Expand Down Expand Up @@ -87,8 +64,6 @@ int main(int argc, char* argv[]) {
curs_set(FALSE);

// -- simulation setup --------------------------------------------------
const unsigned int num_threads = std::thread::hardware_concurrency();

int max_x = 0;
int max_y = 0;
getmaxyx(stdscr, max_y, max_x);
Expand Down Expand Up @@ -121,7 +96,7 @@ int main(int argc, char* argv[]) {
}

refresh();
update_boids(boids, num_threads);
update_boids(boids);
std::this_thread::sleep_for(std::chrono::milliseconds(delay_ms));
}

Expand Down

0 comments on commit 74fe8ab

Please sign in to comment.