-
-
Notifications
You must be signed in to change notification settings - Fork 29
Threading
Romain Milbert edited this page Nov 1, 2022
·
8 revisions
A thread pool object can be used to execute actions on different threads. The concept of a thread pool is a collection of threads running endlessly, to which you can give actions to execute.
#include <RaZ/Utils/ThreadPool.hpp>
// A thread pool can be created by giving a specific number of threads, or nothing to get the default amount
Raz::ThreadPool threadPool; // Equivalent to Raz::ThreadPool threadPool(Raz::Threading::getSystemThreadCount());
// Actions can be pushed to the pool using the addAction() member function:
int i = 0;
threadPool.addAction([&i] () { i = 42; });
// The variable i will be equal to 42 anytime. However, since it is asynchronous, there is no guarantee
// that the value will immediately be set, so using it directly after this call may provoke a data race
threadPool.addAction([&i] () { i = 3; });
// For the same reason, this other function is dangerous: nothing requires that i will be set first to 42,
// then to 3. Specific action must be taken, like setting up a mutex or making i an atomic variable
A "default" thread pool, created with the default thread count & used for other parallel algorithms, is available through Raz::Threading::getDefaultThreadPool()
.
Actions can be performed by multiple threads, either individually or over separate ranges of any collection:
#include <RaZ/Utils/Threading.hpp>
// Executing an action on 4 different threads. Be careful about data concurrency!
Raz::Threading::parallelize([] () { ... }, 4);
std::array<int, 5> values = { 1, 2, 3, 4, 5 };
// Incrementing all elements in the array on multiple threads
// No overlap between values is created, making this function thread safe for the given collection
// This of course works even when giving a number of threads not divisible by the collection's size
Raz::Threading::parallelize(0, values.size(), [&values] (const Raz::Threading::IndexRange& range) {
for (std::size_t i = range.beginIndex; i < range.endIndex; ++i)
++values[i];
}, 4);
// You can also give two iterators to iterate over. In the example below, 'values' could have
// been strictly replaced by 'values.begin(), values.end()'
// Strongly consider the use of 'const auto& range' instead of specifying the whole type
Raz::Threading::parallelize(values, [] (const Raz::Threading::IterRange<std::array<int, 5>::iterator>& range) {
for (int& val : range)
++val;
}, 4);
These functions block the main thread before exiting, waiting for all threads to finish their tasks, so that you don't have to.
- Home
- How to build RaZ
- Getting started
- General usage knowledge
- Some examples...
- Playground
- Tutorials
- File formats
- Modules
- Debug