English
Summary
Conclusions
In this course, multithreaded C++ programs are built with the GCC 15 compiler using CMake and Ninja: CMake describes a project in terms of targets and generates build.ninja, presets fix the parameters of the Debug and Release configurations, and Ninja compiles files in parallel. The CLion IDE uses the same CMake files and the WSL toolchain with Ubuntu 26.04. Threads are created with the std::thread and std::jthread classes; the latter waits for the thread to finish on its own and supports cooperative cancellation through std::stop_token. Shared data is protected by std::mutex with the lock_guard, unique_lock, scoped_lock, and shared_lock guards; waiting for conditions is implemented with condition_variable, semaphores, latch, and barrier; and simple counters use std::atomic. Results and exceptions are passed between threads with std::future, std::promise, std::packaged_task, and std::async; a thread pool is built on these facilities. In GCC, the parallel algorithms of the standard library with the seq, unseq, par, and par_unseq policies require the TBB library; otherwise, they run sequentially. The C++26 std::execution model is not yet implemented in GCC. Data races are detected by ThreadSanitizer, and time is measured with the steady_clock clock and the perf stat utility.
Self-check questions
- What are the stages of building a C++ project with CMake and Ninja?
- What do the
add_executable,target_compile_features, andtarget_link_librariescommands describe? - Why do you need the
CMakePresets.jsonfile? How do you build a project with a preset? - What are a toolchain and a CMake profile in CLion? How do the MinGW and WSL toolchains differ?
- How does
std::jthreaddiffer fromstd::thread? - What happens if you destroy a joinable
std::threadobject? - How do you pass an argument to a thread by reference?
- How does cooperative cancellation through
std::stop_tokenwork? - How do
lock_guard,unique_lock,scoped_lock, andshared_lockdiffer? - Why does a condition variable need a predicate?
- What are
counting_semaphore,latch, andbarrierfor? - How does the
compare_exchange_weakoperation work? Why is it called in a loop? - How do the
std::launch::asyncandstd::launch::deferredpolicies differ? - How is an exception from a thread passed through
std::future? - What parts does a thread pool consist of?
- How do the
seq,unseq,par, andpar_unseqexecution policies differ? - What role does the TBB library play for the parallel algorithms of GCC?
- How do you find a data race with ThreadSanitizer?
Useful links
- The C++ thread support library: https://en.cppreference.com/w/cpp/thread
- Execution policies: https://en.cppreference.com/w/cpp/algorithm/execution_policy_tag_t
- CMake documentation: https://cmake.org/cmake/help/latest/
- CMake presets: https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html
- The Ninja manual: https://ninja-build.org/manual.html
- GCC documentation: https://gcc.gnu.org/onlinedocs/
- The WSL toolchain in CLion: https://www.jetbrains.com/help/clion/how-to-use-wsl-development-environment-in-product.html
- The oneTBB library: https://github.com/uxlfoundation/oneTBB