new example with histogram thats filled in parallel

This commit is contained in:
Hans Dembinski 2018-11-13 16:06:52 +01:00
parent 2e68e77e4e
commit 4d3f9afb74
4 changed files with 87 additions and 16 deletions

View File

@ -108,6 +108,7 @@ compiled_test(examples/guide_histogram_reduction.cpp)
compiled_test(examples/guide_histogram_streaming.cpp)
compiled_test(examples/guide_make_dynamic_histogram.cpp)
compiled_test(examples/guide_make_static_histogram.cpp)
compiled_test(examples/guide_parallel_filling.cpp)
if (TEST_SERIALIZATION)
compiled_test(examples/guide_histogram_serialization.cpp Boost::serialization)

View File

@ -0,0 +1,71 @@
// Copyright 2015-2018 Hans Dembinski
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
//[ guide_custom_storage
#include <array>
#include <atomic>
#include <boost/histogram.hpp>
#include <boost/histogram/algorithm/sum.hpp>
#include <cassert>
#include <chrono>
#include <functional>
#include <thread>
#include <vector>
namespace bh = boost::histogram;
template <typename Histogram>
void fill(Histogram& h) {
for (unsigned i = 0; i < 1000; ++i) { h(i % 10); }
}
/*
std::atomic has deleted copy ctor, we need to wrap it in a type with a
potentially unsafe copy ctor. It can be used in a thread-safe way if some
rules are followed, see below.
*/
template <typename T>
class copyable_atomic : public std::atomic<T> {
public:
using std::atomic<T>::atomic;
// this is potentially not thread-safe
copyable_atomic(const copyable_atomic& rhs) { this->operator=(rhs); }
// this is potentially not thread-safe
copyable_atomic& operator=(const copyable_atomic& rhs) {
if (this != &rhs) { std::atomic<T>::operator=(rhs.load()); }
return *this;
}
};
int main() {
/*
Create histogram with array<std::atomic<std::size_t>, 100> as counter storage
for parallel filling in several threads. You cannot use std::vector here,
because std::atomic types are not copyable.
*/
auto h = bh::make_histogram_with(std::vector<copyable_atomic<unsigned>>(),
bh::axis::integer<>(0, 10));
/*
The histogram storage may not be resized in either thread. This is the case
if you do not use growing axis types. Some notes regarding std::thread.
- The templated fill function must be instantiated when passed to std::thread
that why we pass fill<decltype(h)>.
- std::thread copies the argument. To avoid filling two copies of the
histogram, we need to pass it via std::ref.
*/
std::thread t1(fill<decltype(h)>, std::ref(h));
std::thread t2(fill<decltype(h)>, std::ref(h));
t1.join();
t2.join();
assert(bh::algorithm::sum(h) == 2000);
}
//]

View File

@ -189,6 +189,8 @@ BOOST_HISTOGRAM_MAKE_SFINAE(is_iterable, (std::begin(std::declval<T&>()),
BOOST_HISTOGRAM_MAKE_SFINAE(is_streamable,
(std::declval<std::ostream&>() << std::declval<T&>()));
BOOST_HISTOGRAM_MAKE_SFINAE(is_incrementable, (++std::declval<T&>()));
template <typename T>
struct is_axis_variant_impl : std::false_type {};

View File

@ -38,19 +38,6 @@ template <typename... Ts>
struct is_accumulator_set<::boost::accumulators::accumulator_set<Ts...>>
: std::true_type {};
// specialized form for arithmetic types
struct element_adaptor_arithmetic {
template <typename T>
static void forward(T& t) {
++t;
}
template <typename T, typename U>
static void forward(T& t, const weight_type<U>& u) {
t += u.value;
}
};
// specialized form for accumulator_set
struct element_adaptor_accumulator_set {
template <typename T>
static void forward(T& t) {
@ -70,7 +57,17 @@ struct element_adaptor_accumulator_set {
}
};
// generic form for aggregator types
struct element_adaptor_incrementable {
template <typename T>
static void forward(T& t) {
++t;
}
template <typename T, typename U>
static void forward(T& t, const weight_type<U>& u) {
t += u.value;
}
};
struct element_adaptor_generic {
template <typename T, typename... Us>
static void forward(T& t, Us&&... us) {
@ -80,8 +77,8 @@ struct element_adaptor_generic {
template <typename T>
using element_adaptor =
mp11::mp_if<std::is_arithmetic<T>, element_adaptor_arithmetic,
mp11::mp_if<is_accumulator_set<T>, element_adaptor_accumulator_set,
mp11::mp_if<is_accumulator_set<T>, element_adaptor_accumulator_set,
mp11::mp_if<detail::is_incrementable<T>, element_adaptor_incrementable,
element_adaptor_generic>>;
template <typename T>