Добрый день. Есть задача обработки элементов вектора. Вектор не очень большой, но и не маленький (в среднем около 5000 элементов, которые являются небольшими изображениями). Решил применить многопоточность и сделать небольшой тестовый пример (максимально упрощенный). Так вот результаты получаются совсем не те, что ожидаются. Вот код: Код | #include <cmath> #include <vector> #include <thread> #include <iostream> #include <functional>
int test(int x) { return x * x; }
void print(const std::vector<int>& v) { for (const auto i : v) { std::cout << i << " "; } std::cout << std::endl; }
void print(std::vector<int>::iterator begin, std::vector<int>::iterator end) { auto it = begin; while (it != end) { std::cout << *it << " "; ++it; } std::cout << std::endl; }
std::vector<int>::iterator for_each(std::vector<int>::iterator first, std::vector<int>::iterator last, std::vector<int>::iterator result, std::function<int(int)> mapFunctor) { while (first != last) { *result = mapFunctor(*first); ++result; ++first; } return result; }
std::vector<int>::iterator mapped(std::vector<int>::iterator first, std::vector<int>::iterator last, std::vector<int>::iterator result, std::function<int(int)> mapFunctor) { auto availableThreads = std::thread::hardware_concurrency(); if (availableThreads < 2) { for_each(first, last, result, mapFunctor); } else { const auto totalSize = std::distance(first, last); const auto blockSize = static_cast<size_t>(std::ceil(1.0 * totalSize / availableThreads)); std::vector<std::thread> threads; std::vector<std::vector<int>> results; auto current = first; for (unsigned int i = 0; i < (availableThreads - 1); ++i) { auto blockStart = current; auto blockEnd = blockStart; std::advance(blockEnd, blockSize); current = blockEnd; results.emplace_back(std::vector<int>(blockSize)); threads.emplace_back( std::thread(for_each, std::ref(blockStart), std::ref(blockEnd), results.at(i).begin(), mapFunctor)); } result = for_each(current, last, result, mapFunctor); for (unsigned int i = 0; i < threads.size(); ++i) { if (threads[i].joinable()) { threads[i].join(); } print(results.at(i)); result = std::copy(results.at(i).begin(), results.at(i).end(), result); } } return result; }
int main() { std::vector<int> v; for (unsigned int i = 1; i < 41; ++i) { v.emplace_back(i); } std::vector<int> v2; v2.resize(v.size()); print(v); mapped(v.begin(), v.end(), v2.begin(), test); print(v2); return 0; }
|
В итоге получаю, примерно, вот такой вывод: Код | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 121 144 169 196 225 121 144 169 196 225 256 289 324 361 400 441 484 529 576 625 676 729 784 841 900 961 1024 1089 1156 1225 961 1024 1089 1156 1225 1296 1369 1444 1521 1600 121 144 169 196 225 121 144 169 196 225 256 289 324 361 400 441 484 529 576 625 676 729 784 841 900 961 1024 1089 1156 1225 961 1024 1089 1156 1225
|
Первая строка это исходные элементы, со второй по восьмую -- результат обработки блоков в разных потоках, девятая -- результирующий вектор. Подскажите, пожалуйста, что я не учел?
|