When using std::ranges::subrange
in multi-threaded code, it's important to understand how subranges interact with shared data.
Subranges themselves are lightweight and non-owning, meaning they do not manage the lifetime of the underlying data. This can lead to potential issues if the underlying container is modified concurrently.
If your std::ranges::subrange
is only being used for read-only access, you can safely use it across multiple threads.
Each thread can iterate over the subrange without modifying the underlying data. For example:
#include <iostream>
#include <ranges>
#include <thread>
#include <vector>
void print_subrange(std::ranges::subrange<
std::vector<int>::iterator> view) {
for (int n : view) {
std::cout << n << ", ";
}
}
int main() {
std::vector<int> Nums{1, 2, 3, 4, 5};
std::ranges::subrange view{Nums};
std::thread t1(print_subrange, view);
std::thread t2(print_subrange, view);
t1.join();
t2.join();
}
1, 2, 3, 4, 5, 1, 2, 3, 4, 5,
If you need to modify the underlying container while using a subrange, you must ensure proper synchronization to avoid data races.
This typically involves using mutexes or other synchronization primitives. For example:
#include <iostream>
#include <mutex>
#include <ranges>
#include <thread>
#include <vector>
std::mutex mtx;
void modify_subrange(std::ranges::subrange<
std::vector<int>::iterator> view) {
std::lock_guard<std::mutex> lock(mtx);
for (int& n : view) {
n += 1;
}
}
int main() {
std::vector<int> Nums{1, 2, 3, 4, 5};
std::ranges::subrange view{Nums};
std::thread t1(modify_subrange, view);
std::thread t2(modify_subrange, view);
t1.join();
t2.join();
for (int n : Nums) {
std::cout << n << ", ";
}
}
3, 4, 5, 6, 7,
Using std::ranges::subrange
in multi-threaded code can be efficient and powerful when done correctly. Always consider the synchronization requirements and the lifetime of the underlying data to avoid race conditions and undefined behavior.
Answers to questions are automatically generated and may not have been reviewed.
std::ranges::subrange
This lesson introduces std::ranges::subrange, allowing us to create non-owning ranges that view some underlying container