Files
concurrency-in-action/source/listing_8.13.cpp
2018-10-18 00:40:34 -05:00

86 lines
2.1 KiB
C++

#include <atomic>
#include <thread>
#include <vector>
struct join_threads {
join_threads(std::vector<std::thread>&) {}
};
struct barrier {
std::atomic<unsigned> count;
std::atomic<unsigned> spaces;
std::atomic<unsigned> generation;
barrier(unsigned count_) : count(count_), spaces(count_), generation(0) {}
void wait()
{
unsigned const gen = generation.load();
if (!--spaces) {
spaces = count.load();
++generation;
}
else {
while (generation.load() == gen) {
std::this_thread::yield();
}
}
}
void done_waiting()
{
--count;
if (!--spaces) {
spaces = count.load();
++generation;
}
}
};
template <typename Iterator>
void
parallel_partial_sum(Iterator first, Iterator last)
{
typedef typename Iterator::value_type value_type;
struct process_element {
void operator()(Iterator first,
Iterator last,
std::vector<value_type>& buffer,
unsigned i,
barrier& b)
{
value_type& ith_element = *(first + i);
bool update_source = false;
for (unsigned step = 0, stride = 1; stride <= i; ++step, stride *= 2) {
value_type const& source = (step % 2) ? buffer[i] : ith_element;
value_type& dest = (step % 2) ? ith_element : buffer[i];
value_type const& addend =
(step % 2) ? buffer[i - stride] : *(first + i - stride);
dest = source + addend;
update_source = !(step % 2);
b.wait();
}
if (update_source) {
ith_element = buffer[i];
}
b.done_waiting();
}
};
unsigned long const length = std::distance(first, last);
if (length <= 1)
return;
std::vector<value_type> buffer(length);
barrier b(length);
std::vector<std::thread> threads(length - 1);
join_threads joiner(threads);
Iterator block_start = first;
for (unsigned long i = 0; i < (length - 1); ++i) {
threads[i] = std::thread(
process_element(), first, last, std::ref(buffer), i, std::ref(b));
}
process_element()(first, last, buffer, length - 1, b);
}