mirror of
https://github.com/boostorg/histogram.git
synced 2025-05-11 13:14:06 +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_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)
|
||||
|
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,
|
||||
(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 {};
|
||||
|
||||
|
@ -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>
|
||||
|
Loading…
x
Reference in New Issue
Block a user