]>
Commit | Line | Data |
---|---|---|
92f5a8d4 TL |
1 | // Copyright 2019 Hans Dembinski |
2 | // | |
3 | // Distributed under the Boost Software License, Version 1.0. | |
4 | // (See accompanying file LICENSE_1_0.txt | |
5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) | |
6 | ||
7 | #ifndef BOOST_HISTOGRAM_ACCUMULATORS_THREAD_SAFE_HPP | |
8 | #define BOOST_HISTOGRAM_ACCUMULATORS_THREAD_SAFE_HPP | |
9 | ||
10 | #include <atomic> | |
11 | #include <boost/core/nvp.hpp> | |
12 | #include <boost/mp11/utility.hpp> | |
13 | #include <type_traits> | |
14 | ||
15 | namespace boost { | |
16 | namespace histogram { | |
17 | namespace accumulators { | |
18 | ||
19 | /** Thread-safe adaptor for builtin integral and floating point numbers. | |
20 | ||
21 | This adaptor uses std::atomic to make concurrent increments and additions safe for the | |
22 | stored value. | |
23 | ||
24 | On common computing platforms, the adapted integer has the same size and | |
25 | alignment as underlying type. The atomicity is implemented with a special CPU | |
26 | instruction. On exotic platforms the size of the adapted number may be larger and/or the | |
27 | type may have different alignment, which means it cannot be tightly packed into arrays. | |
28 | ||
29 | @tparam T type to adapt, must be supported by std::atomic. | |
30 | */ | |
31 | template <class T> | |
32 | class thread_safe : public std::atomic<T> { | |
33 | public: | |
34 | using value_type = T; | |
35 | using super_t = std::atomic<T>; | |
36 | ||
37 | thread_safe() noexcept : super_t(static_cast<T>(0)) {} | |
38 | // non-atomic copy and assign is allowed, because storage is locked in this case | |
39 | thread_safe(const thread_safe& o) noexcept : super_t(o.load()) {} | |
40 | thread_safe& operator=(const thread_safe& o) noexcept { | |
41 | super_t::store(o.load()); | |
42 | return *this; | |
43 | } | |
44 | ||
45 | thread_safe(value_type arg) : super_t(arg) {} | |
46 | thread_safe& operator=(value_type arg) { | |
47 | super_t::store(arg); | |
48 | return *this; | |
49 | } | |
50 | ||
51 | thread_safe& operator+=(const thread_safe& arg) { | |
52 | operator+=(arg.load()); | |
53 | return *this; | |
54 | } | |
55 | thread_safe& operator+=(value_type arg) { | |
56 | super_t::fetch_add(arg, std::memory_order_relaxed); | |
57 | return *this; | |
58 | } | |
59 | thread_safe& operator++() { | |
60 | operator+=(static_cast<value_type>(1)); | |
61 | return *this; | |
62 | } | |
63 | ||
64 | template <class Archive> | |
65 | void serialize(Archive& ar, unsigned /* version */) { | |
66 | auto value = super_t::load(); | |
67 | ar& make_nvp("value", value); | |
68 | super_t::store(value); | |
69 | } | |
70 | }; | |
71 | ||
72 | } // namespace accumulators | |
73 | } // namespace histogram | |
74 | } // namespace boost | |
75 | ||
76 | #endif |