Wielowątkowe accumulate, klopot

0
#include <iostream>
#include <thread>
#include <vector>
#include <numeric>
#include <functional>
#include <algorithm>

template <typename Iterator, typename T>
struct accumulate_block
{
	void operator()(Iterator first, Iterator last, T &result)
	{
		result = std::accumulate(first, last, result);
	}
};

template <typename Iterator, typename T>
T parallel_accumulate(Iterator first, Iterator last, T init)
{
	unsigned long const lenght = std::distance(first, last);

	if (!lenght)
		return init;

	unsigned long const min_per_thread = 25;
	unsigned long const max_threads = (lenght + min_per_thread - 1) / min_per_thread;

	unsigned long const num_threads = std::min(hardware_threads != 0 ? hardware_threads : 2, max_threads);

	unsigned long const block_size = lenght / num_threads;

	std::vector<T> results(num_threads);
	std::vector<std::thread> threads(num_threads - 1);

	Iterator block_start = first;
	for (unsigned long i = 0; i < (num_threads - 1); ++i)
	{
		Iterator block_end = block_start;
		std::advance(block_end, block_size);
		threads[i] = std::thread(accumulate_block<Iterator, T>(),
			block_start, block_end, std::ref(results[i]));
		block_start = block_end;
	}
	accumulate_block<Iterator, T>()(block_start, last, results[num_threads - 1]);
	std::for_each(threads.begin(), thread.end(), std::mem_fn(&std::thread::join));

	return std::accumulate(results.begin(), results.end(), init);
}

int main()
{
	std::vector<int> vec = {1, 2, 3, 4, 5, 0, 1};
	std::cout << parallel_accumulate(vec.begin(), vec.end(), 0) << std::endl;

	system("pause");
	return 0;
} 

Mam tu kod z pewnej książki, który robi wielowątkowo operację std::accumulate. Niestety nie działa, nie wiem dlaczego, a przez wielowątkowość, to wyskakują kompletnie nieintuicyjne, ciężkie do analizy błędy.

998f65f881.png

1

Jakiego typu jest hardware_threads bo pewnie nie unsigned long const? A typy powinny być takie same.

std::for_each(threads.begin(), thread.end(), std::mem_fn(&std::thread::join));

tutaj zamiast thread.end() miało być chyba threads.end().

0

Z tym threads.end() masz rację. Poprawiłem. Z tym hardware_threads to chyba może być unsigned const. Nie widzę problemu. Ogólnie to liczba błędów zmniejszyła się teraz do takiej.

d527c46f6f.png

0
#include <iostream>
#include <thread>
#include <vector>
#include <numeric>
#include <functional>
#include <algorithm>

template <typename Iterator, typename T>
struct accumulate_block
{
	void operator()(Iterator first, Iterator last, T &result)
	{
		result = std::accumulate(first, last, result);
	}
};

template <typename Iterator, typename T>
T parallel_accumulate(Iterator first, Iterator last, T init)
{
	unsigned long const lenght = std::distance(first, last);

	if (!lenght)
		return init;

	unsigned long const min_per_thread = 25;
	unsigned long const max_threads = (lenght + min_per_thread - 1) / min_per_thread;

	unsigned long const hardware_threads = std::thread::hardware_concurrency();

	unsigned long const num_threads = std::min(hardware_threads != 0 ? hardware_threads : 2, max_threads);

	unsigned long const block_size = lenght / num_threads;

	std::vector<T> results(num_threads);
	std::vector<std::thread> threads(num_threads - 1);

	Iterator block_start = first;
	for (unsigned long i = 0; i < (num_threads - 1); ++i)
	{
		Iterator block_end = block_start;
		std::advance(block_end, block_size);
		threads[i] = std::thread(accumulate_block<Iterator, T>(),
			block_start, block_end, std::ref(results[i]));
		block_start = block_end;
	}
	accumulate_block<Iterator, T>()(block_start, last, results[num_threads - 1]);
	std::for_each(threads.begin(), threads.end(), std::mem_fn(&std::thread::join));

	return std::accumulate(results.begin(), results.end(), init);
}

int main()
{
	std::vector<int> vec = {1, 2, 3, 4, 5, 0, 1};
	std::cout << parallel_accumulate(vec.begin(), vec.end(), 0) << std::endl;

	system("pause");
	return 0;
} 

Dobra, dzięki. Już wszystko jasne. Powyżej jest działający kod.

1 użytkowników online, w tym zalogowanych: 0, gości: 1