1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
|
#ifndef DataFormats_Common_AtomicPtrCache_h
#define DataFormats_Common_AtomicPtrCache_h
// -*- C++ -*-
//
// Package: DataFormats/Common
// Class : AtomicPtrCache
//
/**\class edm::AtomicPtrCache AtomicPtrCache.h "DataFormats/Common/interface/AtomicPtrCache.h"
Description: A thread safe cache managed by a pointer
Usage:
Data products which need to cache results into non-trivial structures (e.g. an std::vector)
can use this class to manage the cache in a thread-safe way.
The thread-safety guarantee is only the standard C++, if calls are made to const functions simultaneously
then everything is thread safe. Calling a non-const function while calling any other functions
is not thread-safe.
This class also hides the std::atomic from ROOT so this class can safely be used in a stored class.
WARNING: member data which uses this class must be made transient in the classes_def.xml file!
*/
//
// Original Author: Chris Jones
// Created: Thu, 07 Nov 2013 00:50:40 GMT
//
// system include files
#include <atomic>
#include <memory>
// user include files
// forward declarations
namespace edm {
template <typename T>
class AtomicPtrCache {
public:
AtomicPtrCache();
///Takes exclusive ownership of the value
explicit AtomicPtrCache(T*);
///Uses T's copy constructor to make a copy
AtomicPtrCache(const AtomicPtrCache<T>&);
AtomicPtrCache& operator=(const AtomicPtrCache<T>&);
~AtomicPtrCache();
// ---------- const member functions ---------------------
T const* operator->() const { return load(); }
T const& operator*() const { return *load(); }
T const* load() const;
bool isSet() const;
///returns true if actually was set.
/// Will delete value held by iNewValue if not the first time set
bool set(std::unique_ptr<T> iNewValue) const;
// ---------- static member functions --------------------
// ---------- member functions ---------------------------
T* operator->() { return load(); }
T& operator*() { return *load(); }
T* load();
///unsets the value and deletes the memory
void reset();
T* release();
private:
// ---------- member data --------------------------------
mutable std::atomic<T*> m_data;
};
template <typename T>
inline AtomicPtrCache<T>::AtomicPtrCache() : m_data{nullptr} {}
template <typename T>
inline AtomicPtrCache<T>::AtomicPtrCache(T* iValue) : m_data{iValue} {}
template <typename T>
inline AtomicPtrCache<T>::AtomicPtrCache(const AtomicPtrCache<T>& iOther) : m_data{nullptr} {
auto ptr = iOther.m_data.load(std::memory_order_acquire);
if (ptr != nullptr) {
m_data.store(new T{*ptr}, std::memory_order_release);
}
}
template <typename T>
inline AtomicPtrCache<T>& AtomicPtrCache<T>::operator=(const AtomicPtrCache<T>& iOther) {
auto ptr = iOther.m_data.load(std::memory_order_acquire);
if (ptr != nullptr) {
auto ourPtr = m_data.load(std::memory_order_acquire);
if (ourPtr != nullptr) {
*ourPtr = *ptr;
} else {
m_data.store(new T{*ptr}, std::memory_order_release);
}
} else {
delete m_data.exchange(nullptr, std::memory_order_acq_rel);
}
return *this;
}
template <typename T>
inline AtomicPtrCache<T>::~AtomicPtrCache() {
delete m_data.load(std::memory_order_acquire);
}
template <typename T>
inline T* AtomicPtrCache<T>::load() {
return m_data.load(std::memory_order_acquire);
}
template <typename T>
inline T const* AtomicPtrCache<T>::load() const {
return m_data.load(std::memory_order_acquire);
}
template <typename T>
inline bool AtomicPtrCache<T>::isSet() const {
return nullptr != m_data.load(std::memory_order_acquire);
}
template <typename T>
inline bool AtomicPtrCache<T>::set(std::unique_ptr<T> iNewValue) const {
bool retValue;
T* expected = nullptr;
if ((retValue = m_data.compare_exchange_strong(expected, iNewValue.get(), std::memory_order_acq_rel))) {
iNewValue.release();
}
return retValue;
}
template <typename T>
inline void AtomicPtrCache<T>::reset() {
delete m_data.exchange(nullptr, std::memory_order_acq_rel);
}
template <typename T>
inline T* AtomicPtrCache<T>::release() {
T* tmp = m_data.exchange(nullptr);
return tmp;
}
} // namespace edm
#endif
|