fix for threading bug

This commit is contained in:
Hans Dembinski 2019-04-16 23:01:00 +02:00
parent 45a4ae1e19
commit 7b88f02f0e
2 changed files with 28 additions and 29 deletions

View File

@ -107,7 +107,7 @@ void linearize_index(optional_index& out, const A& axis, const axis::index_type
} }
template <class S, class A> template <class S, class A>
void grow_storage(S& storage, const A& axes, const axis::index_type* shifts) { void grow_storage(const A& axes, S& storage, const axis::index_type* shifts) {
struct item { struct item {
axis::index_type idx, old_extent; axis::index_type idx, old_extent;
std::size_t new_stride; std::size_t new_stride;
@ -177,8 +177,8 @@ void grow_storage(S& storage, const A& axes, const axis::index_type* shifts) {
// interface), so we throw at runtime if incompatible argument is passed (e.g. // interface), so we throw at runtime if incompatible argument is passed (e.g.
// 3d tuple) // 3d tuple)
// histogram has only non-growing axes // histogram has only non-growing axes
template <unsigned I, unsigned N, class S, class T, class U> template <unsigned I, unsigned N, class T, class S, class U>
optional_index args_to_index(std::false_type, S&, const T& axes, const U& args) { optional_index to_index(std::false_type, const T& axes, S&, const U& args) {
optional_index idx; optional_index idx;
const auto rank = get_size(axes); const auto rank = get_size(axes);
if (rank == 1 && N > 1) if (rank == 1 && N > 1)
@ -196,13 +196,12 @@ optional_index args_to_index(std::false_type, S&, const T& axes, const U& args)
} }
// histogram has growing axes // histogram has growing axes
template <unsigned I, unsigned N, class S, class T, class U> template <unsigned I, unsigned N, class T, class S, class U>
optional_index args_to_index(std::true_type, S& storage_and_mutex, T& axes, optional_index to_index(std::true_type, T& axes, S& storage, const U& args) {
const U& args) {
optional_index idx; optional_index idx;
axis::index_type shifts[buffer_size<T>::value]; constexpr unsigned M = buffer_size<T>::value;
axis::index_type shifts[M];
const auto rank = get_size(axes); const auto rank = get_size(axes);
std::lock_guard<typename S::second_type> lk{storage_and_mutex.second()};
bool update_needed = false; bool update_needed = false;
if (rank == 1 && N > 1) if (rank == 1 && N > 1)
update_needed = update_needed =
@ -211,14 +210,13 @@ optional_index args_to_index(std::true_type, S& storage_and_mutex, T& axes,
if (rank != N) if (rank != N)
BOOST_THROW_EXCEPTION( BOOST_THROW_EXCEPTION(
std::invalid_argument("number of arguments != histogram rank")); std::invalid_argument("number of arguments != histogram rank"));
constexpr unsigned M = buffer_size<remove_cvref_t<decltype(axes)>>::value;
mp11::mp_for_each<mp11::mp_iota_c<(N < M ? N : M)>>([&](auto J) { mp11::mp_for_each<mp11::mp_iota_c<(N < M ? N : M)>>([&](auto J) {
update_needed |= update_needed |=
linearize_value(idx, shifts[J], axis_get<J>(axes), std::get<(J + I)>(args)); linearize_value(idx, shifts[J], axis_get<J>(axes), std::get<(J + I)>(args));
}); });
} }
if (update_needed) grow_storage(storage_and_mutex.first(), axes, shifts); if (update_needed) grow_storage(axes, storage, shifts);
return idx; return idx;
} }
@ -257,57 +255,58 @@ constexpr auto weight_sample_indices() {
} }
template <class T> template <class T>
void fill_storage2(std::true_type, T&& t) { void fill_impl2(std::true_type, T&& t) {
++t; ++t;
} }
template <class T, class U> template <class T, class U>
void fill_storage2(std::true_type, T&& t, const U& u) { void fill_impl2(std::true_type, T&& t, const U& u) {
t += u; t += u;
} }
template <class T, class... Us> template <class T, class... Us>
void fill_storage2(std::false_type, T&& t, const Us&... us) { void fill_impl2(std::false_type, T&& t, const Us&... us) {
t(us...); t(us...);
} }
template <class T, class U> template <class T, class U>
void fill_storage(mp11::mp_int<-1>, mp11::mp_int<-1>, T&& t, const U&) { void fill_impl1(mp11::mp_int<-1>, mp11::mp_int<-1>, T&& t, const U&) {
fill_storage2(has_operator_preincrement<remove_cvref_t<T>>{}, t); fill_impl2(has_operator_preincrement<remove_cvref_t<T>>{}, t);
} }
template <class IW, class T, class U> template <class IW, class T, class U>
void fill_storage(IW, mp11::mp_int<-1>, T&& t, const U& u) { void fill_impl1(IW, mp11::mp_int<-1>, T&& t, const U& u) {
fill_storage2(has_operator_preincrement<remove_cvref_t<T>>{}, t, fill_impl2(has_operator_preincrement<remove_cvref_t<T>>{}, t,
std::get<IW::value>(u).value); std::get<IW::value>(u).value);
} }
template <class IS, class T, class U> template <class IS, class T, class U>
void fill_storage(mp11::mp_int<-1>, IS, T&& t, const U& u) { void fill_impl1(mp11::mp_int<-1>, IS, T&& t, const U& u) {
mp11::tuple_apply([&t](auto&&... args) { t(args...); }, std::get<IS::value>(u).value); mp11::tuple_apply([&t](auto&&... args) { t(args...); }, std::get<IS::value>(u).value);
} }
template <class IW, class IS, class T, class U> template <class IW, class IS, class T, class U>
void fill_storage(IW, IS, T&& t, const U& u) { void fill_impl1(IW, IS, T&& t, const U& u) {
mp11::tuple_apply([&](auto&&... args2) { t(std::get<IW::value>(u).value, args2...); }, mp11::tuple_apply([&](auto&&... args2) { t(std::get<IW::value>(u).value, args2...); },
std::get<IS::value>(u).value); std::get<IS::value>(u).value);
} }
template <class S, class A, class... Us> template <class A, class SM, class... Us>
auto fill(S& storage_and_mutex, A& axes, const std::tuple<Us...>& args) { typename SM::first_type::iterator fill(A& axes, SM& sm, const std::tuple<Us...>& tus) {
constexpr auto iws = weight_sample_indices<Us...>(); constexpr auto iws = weight_sample_indices<Us...>();
constexpr unsigned n = sizeof...(Us) - (iws.first > -1) - (iws.second > -1); constexpr unsigned n = sizeof...(Us) - (iws.first > -1) - (iws.second > -1);
constexpr unsigned i = (iws.first == 0 || iws.second == 0) constexpr unsigned i = (iws.first == 0 || iws.second == 0)
? (iws.first == 1 || iws.second == 1 ? 2 : 1) ? (iws.first == 1 || iws.second == 1 ? 2 : 1)
: 0; : 0;
optional_index idx = std::lock_guard<typename SM::second_type> lk{sm.second()};
args_to_index<i, n>(has_growing_axis<A>(), storage_and_mutex, axes, args); auto& storage = sm.first();
optional_index idx = to_index<i, n>(has_growing_axis<A>(), axes, storage, tus);
if (idx) { if (idx) {
fill_storage(mp11::mp_int<iws.first>{}, mp11::mp_int<iws.second>{}, using mp11::mp_int;
storage_and_mutex.first()[*idx], args); fill_impl1(mp_int<iws.first>{}, mp_int<iws.second>{}, storage[*idx], tus);
return storage_and_mutex.first().begin() + *idx; return storage.begin() + *idx;
} }
return storage_and_mutex.first().end(); return storage.end();
} }
template <typename A, typename... Us> template <typename A, typename... Us>

View File

@ -181,7 +181,7 @@ public:
/// Fill histogram with values, an optional weight, and/or a sample from a `std::tuple`. /// Fill histogram with values, an optional weight, and/or a sample from a `std::tuple`.
template <class... Ts> template <class... Ts>
auto operator()(const std::tuple<Ts...>& t) { auto operator()(const std::tuple<Ts...>& t) {
return detail::fill(storage_and_mutex_, axes_, t); return detail::fill(axes_, storage_and_mutex_, t);
} }
/// Access cell value at integral indices. /// Access cell value at integral indices.