FastJet
3.5.2
Toggle main menu visibility
Loading...
Searching...
No Matches
include
fastjet
internal
thread_safety_helpers.hh
1
//FJSTARTHEADER
2
// $Id$
3
//
4
// Copyright (c) 2014-2026, Matteo Cacciari, Gavin P. Salam and Gregory Soyez
5
//
6
//----------------------------------------------------------------------
7
// This file is part of FastJet.
8
//
9
// FastJet is free software; you can redistribute it and/or modify
10
// it under the terms of the GNU General Public License as published by
11
// the Free Software Foundation; either version 2 of the License, or
12
// (at your option) any later version.
13
//
14
// The algorithms that underlie FastJet have required considerable
15
// development. They are described in the original FastJet paper,
16
// hep-ph/0512210 and in the manual, arXiv:1111.6097. If you use
17
// FastJet as part of work towards a scientific publication, please
18
// quote the version you use and include a citation to the manual and
19
// optionally also to hep-ph/0512210.
20
//
21
// FastJet is distributed in the hope that it will be useful,
22
// but WITHOUT ANY WARRANTY; without even the implied warranty of
23
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24
// GNU General Public License for more details.
25
//
26
// You should have received a copy of the GNU General Public License
27
// along with FastJet. If not, see <http://www.gnu.org/licenses/>.
28
//----------------------------------------------------------------------
29
//FJENDHEADER
30
31
#ifndef __FASTJET_THREAD_SAFETY_HELPERS_HH__
32
#define __FASTJET_THREAD_SAFETY_HELPERS_HH__
33
34
/// The code in this file is supposed to help writing code that will
35
/// automatically provide thread-safe features when available and come
36
/// revert back to "old/standard" C++ if thread-safety is not switched
37
/// on
38
///
39
///\TODO fix doxygen comments (declare things as internal; make sure
40
/// doxygen doc is not duplicate --- if necessary, keep only doxygen
41
/// comments in the thread-safe versions)
42
43
#include "fastjet/internal/base.hh"
44
#include "fastjet/config.h"
45
#include <limits>
46
47
#ifdef FASTJET_HAVE_LIMITED_THREAD_SAFETY
48
49
// introduces a few tools in CXX11 that we'll use in some FJ classes
50
#include <atomic>
51
52
FASTJET_BEGIN_NAMESPACE
// defined in fastjet/internal/base.hh
53
54
namespace
thread_safety_helpers{
55
56
//----------------------------------------------------------------------
57
/// \if internal_doc
58
/// \class AtomicCounter
59
///
60
/// provides a thread-safe counter which can only step one unit at a time
61
/// and has overflow protection
62
/// \endif
63
template
<
typename
T>
64
class
AtomicCounter{
65
public
:
66
/// default ctor
67
AtomicCounter() : _count{0}{}
68
69
/// ctor with initialisation
70
AtomicCounter(
const
T &count) : _count{count}{}
71
72
/// copy ctor (works around the deleted copy in atomic, see
73
/// e.g. http://stackoverflow.com/questions/19883092/error-implicitly-deleted-because-the-default-definition-would-be-ill-formed-ve)
74
AtomicCounter(
const
AtomicCounter &other) : _count{other._count.load()}{}
75
76
/// for a more friendly usage, overload the type cast to the
77
/// base template type
78
operator
T()
const
{
return
_count.load();}
79
80
/// get the count
81
T get()
const
{
return
_count.load();}
82
83
/// set the counter to a given value
84
void
set(
const
T new_value){
85
_count.store(new_value);
86
}
87
88
/// step the counter and return the count just before it was stepped
89
///
90
/// Q: can we declare this as T && ...?
91
T step(){
92
// another thread could be upadting this at the same time, so extra
93
// care is needed.
94
//
95
// Recall that the compare_exchange_strong will return true if the
96
// exchange has been done. Otherwise, it means that the count
97
// changed in the meantime, so we try again. Also, since when it
98
// "fails" compare_exchange_strong loads the count of *this in
99
// expected, count does not need to be re-read in the loop!
100
//
101
// Note that at the end of this procedure, count will countain the
102
// number of times this warning occured just before this
103
// occurence. It can thus be used to see if it needs to be printed
104
// out
105
//
106
// Note also that compared to the apparently simpler fetch_add,
107
// this method also avoids overflows
108
T count = _count;
109
while
(_count < std::numeric_limits<T>::max()
110
&& !(_count.compare_exchange_strong(count, count+1)));
111
return
count;
112
}
113
114
/// override the ++ operator
115
/// prefix version
116
inline
T operator++(){
117
return
step()+1;
118
}
119
120
/// override the ++ operator
121
/// postfix version
122
inline
T operator++(
int
){
123
return
step();
124
}
125
126
private
:
127
std::atomic<T> _count;
///< the actual count
128
};
129
130
//----------------------------------------------------------------------
131
/// \if internal_doc
132
/// \class FirstTimeTrue
133
/// provides an object wich will return "true" the first time () is
134
/// called and false afterwards
135
/// \endif
136
class
FirstTimeTrue{
137
public
:
138
FirstTimeTrue(): _first_time{true}{}
139
// explicit copy ctor (this class contains atimoc vars)
140
FirstTimeTrue(
const
FirstTimeTrue &other) : _first_time{other._first_time.load()}{}
141
bool
operator()(){
142
// Thread-safety note:
143
// the construct
144
// if (!_first_time) {return;}
145
// _first_time = false;
146
// is dangerous because the test can be passed by a second thread
147
// before the first one has set it to false. Use atomic exchange
148
// to handle this better
149
bool
expected =
true
;
150
// this behaves as follows: if we have the expected value (true),
151
// set _first_time to the desired (false) and return
152
// true. Otherwise, do nothing and return false
153
//
154
// Note that since we are not using the "expected" value
155
// afterwards, we can use a relaxed memory ordering if the next
156
// call returns false
157
return
_first_time.compare_exchange_strong(expected,
false
,
158
std::memory_order_seq_cst,
159
std::memory_order_relaxed);
160
}
161
private
:
162
std::atomic<bool> _first_time;
163
};
164
165
}
// namespace thread_safety_helpers
166
167
FASTJET_END_NAMESPACE
168
169
#else
// FJ wo thread-safety features
170
171
FASTJET_BEGIN_NAMESPACE
// defined in fastjet/internal/base.hh
172
173
namespace
thread_safety_helpers{
174
//----------------------------------------------------------------------
175
/// \class AtomicCounter
176
///
177
/// (would) provides a thread-safe counter (with CXX11 features)
178
template
<
typename
T>
179
class
AtomicCounter
{
180
public
:
181
/// default ctor
182
AtomicCounter
() : _count(0){}
183
184
/// ctor with initialisation
185
AtomicCounter
(
const
T &count) : _count(count){}
186
187
/// copy ctor
188
AtomicCounter
(
const
AtomicCounter
&other) : _count(other._count){}
189
190
/// for a more friendly usage, overload the type cast
191
///
192
/// This will (likely) allow a transparent usage w or wo C++11
193
/// features enabled
194
operator
T()
const
{
return
_count;}
195
196
/// get the count
197
T
get
()
const
{
return
_count;}
198
199
/// set the counter to a given value
200
void
set
(
const
T new_value){
201
_count = new_value;
202
}
203
204
/// step the counter and return the value just before it was stepped
205
T
step
(){
206
unsigned
int
count = _count;
207
if
(_count < std::numeric_limits<T>::max()){ _count++; }
208
return
count;
209
}
210
211
/// override the ++ operator
212
/// prefix version
213
inline
T
operator++
(){
214
return
step
()+1;
215
}
216
217
/// override the ++ operator
218
/// postfix version
219
inline
T
operator++
(
int
){
220
return
step
();
221
}
222
223
private
:
224
T _count;
///< the actual value
225
};
226
227
//----------------------------------------------------------------------
228
/// \class FirstTimeTrue
229
/// provides an object wich will return "true" the first time () is
230
/// called and false afterwards
231
class
FirstTimeTrue{
232
public
:
233
FirstTimeTrue(): _first_time(
true
){}
234
bool
operator()(){
235
if
(!_first_time) {
return
false
;}
236
_first_time =
false
;
237
return
true
;
238
}
239
private
:
240
bool
_first_time;
241
};
242
}
// namespace thread_safety_helpers
243
244
FASTJET_END_NAMESPACE
245
246
247
248
#endif
// FASTJET_HAVE_LIMITED_THREAD_SAFETY
249
250
#endif
// __FASTJET_THREAD_SAFETY_HELPERS_HH__
fastjet::thread_safety_helpers::AtomicCounter::AtomicCounter
AtomicCounter()
default ctor
Definition
thread_safety_helpers.hh:182
fastjet::thread_safety_helpers::AtomicCounter::AtomicCounter
AtomicCounter(const AtomicCounter &other)
copy ctor
Definition
thread_safety_helpers.hh:188
fastjet::thread_safety_helpers::AtomicCounter::set
void set(const T new_value)
set the counter to a given value
Definition
thread_safety_helpers.hh:200
fastjet::thread_safety_helpers::AtomicCounter::step
T step()
step the counter and return the value just before it was stepped
Definition
thread_safety_helpers.hh:205
fastjet::thread_safety_helpers::AtomicCounter::operator++
T operator++()
override the ++ operator prefix version
Definition
thread_safety_helpers.hh:213
fastjet::thread_safety_helpers::AtomicCounter::operator++
T operator++(int)
override the ++ operator postfix version
Definition
thread_safety_helpers.hh:219
fastjet::thread_safety_helpers::AtomicCounter::AtomicCounter
AtomicCounter(const T &count)
ctor with initialisation
Definition
thread_safety_helpers.hh:185
fastjet::thread_safety_helpers::AtomicCounter::get
T get() const
get the count
Definition
thread_safety_helpers.hh:197
Generated on
for FastJet by
1.18.0