mirror of
https://github.com/boostorg/histogram.git
synced 2025-05-12 13:41:48 +00:00
new example with histogram thats filled in parallel
This commit is contained in:
parent
2e68e77e4e
commit
4d3f9afb74
@ -108,6 +108,7 @@ compiled_test(examples/guide_histogram_reduction.cpp)
|
|||||||
compiled_test(examples/guide_histogram_streaming.cpp)
|
compiled_test(examples/guide_histogram_streaming.cpp)
|
||||||
compiled_test(examples/guide_make_dynamic_histogram.cpp)
|
compiled_test(examples/guide_make_dynamic_histogram.cpp)
|
||||||
compiled_test(examples/guide_make_static_histogram.cpp)
|
compiled_test(examples/guide_make_static_histogram.cpp)
|
||||||
|
compiled_test(examples/guide_parallel_filling.cpp)
|
||||||
|
|
||||||
if (TEST_SERIALIZATION)
|
if (TEST_SERIALIZATION)
|
||||||
compiled_test(examples/guide_histogram_serialization.cpp Boost::serialization)
|
compiled_test(examples/guide_histogram_serialization.cpp Boost::serialization)
|
||||||
|
71
examples/guide_parallel_filling.cpp
Normal file
71
examples/guide_parallel_filling.cpp
Normal 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
//]
|
@ -189,6 +189,8 @@ BOOST_HISTOGRAM_MAKE_SFINAE(is_iterable, (std::begin(std::declval<T&>()),
|
|||||||
BOOST_HISTOGRAM_MAKE_SFINAE(is_streamable,
|
BOOST_HISTOGRAM_MAKE_SFINAE(is_streamable,
|
||||||
(std::declval<std::ostream&>() << std::declval<T&>()));
|
(std::declval<std::ostream&>() << std::declval<T&>()));
|
||||||
|
|
||||||
|
BOOST_HISTOGRAM_MAKE_SFINAE(is_incrementable, (++std::declval<T&>()));
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct is_axis_variant_impl : std::false_type {};
|
struct is_axis_variant_impl : std::false_type {};
|
||||||
|
|
||||||
|
@ -38,19 +38,6 @@ template <typename... Ts>
|
|||||||
struct is_accumulator_set<::boost::accumulators::accumulator_set<Ts...>>
|
struct is_accumulator_set<::boost::accumulators::accumulator_set<Ts...>>
|
||||||
: std::true_type {};
|
: 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 {
|
struct element_adaptor_accumulator_set {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static void forward(T& 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 {
|
struct element_adaptor_generic {
|
||||||
template <typename T, typename... Us>
|
template <typename T, typename... Us>
|
||||||
static void forward(T& t, Us&&... us) {
|
static void forward(T& t, Us&&... us) {
|
||||||
@ -80,8 +77,8 @@ struct element_adaptor_generic {
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using element_adaptor =
|
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>>;
|
element_adaptor_generic>>;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user