Arcane  4.1.12.0
User documentation
Loading...
Searching...
No Matches
StdThreadImplementation.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2026 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* StdThreadImplementation.cc (C) 2000-2026 */
9/* */
10/* Implementation of threads using the standard C++ library. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arccore/base/NotImplementedException.h"
15#include "arccore/base/IFunctor.h"
17#include "arccore/base/NotSupportedException.h"
18#include "arccore/base/Ref.h"
19
20#include "arccore/concurrency/internal/ConcurrencyGlobalInternal.h"
21#include "arccore/concurrency/IThreadBarrier.h"
22#include "arccore/concurrency/Mutex.h"
23
24#include <thread>
25#include <condition_variable>
26#include <mutex>
27#include <barrier>
28
29/*---------------------------------------------------------------------------*/
30/*---------------------------------------------------------------------------*/
31
32namespace Arcane::Concurrency
33{
34
35/*---------------------------------------------------------------------------*/
36/*---------------------------------------------------------------------------*/
37
38/*!
39 * \brief Implementation of ITreadImplementation using the standard C++ library.
40 */
41class ARCCORE_CONCURRENCY_EXPORT StdThreadImplementation
44{
46
47 public:
48
49 explicit StdThreadImplementation(bool use_legacy_barrier);
50 ~StdThreadImplementation() override;
51
52 public:
53
54 void initialize() override;
55
56 public:
57
58 ThreadImpl* createThread(IFunctor* f) override;
59 void joinThread(ThreadImpl* t) override;
60 void destroyThread(ThreadImpl* t) override;
61
62 void createSpinLock(Int64* spin_lock_addr) override;
63 void lockSpinLock(Int64* spin_lock_addr, Int64* scoped_spin_lock_addr) override;
64 void unlockSpinLock(Int64* spin_lock_addr, Int64* scoped_spin_lock_addr) override;
65
66 MutexImpl* createMutex() override;
67 void destroyMutex(MutexImpl*) override;
68 void lockMutex(MutexImpl* mutex) override;
69 void unlockMutex(MutexImpl* mutex) override;
70
71 Int64 currentThread() override;
72
73 IThreadBarrier* createBarrier() override;
74
75 public:
76
77 void addReference() override { ReferenceCounterImpl::addReference(); }
78 void removeReference() override { ReferenceCounterImpl::removeReference(); }
79
80 private:
81
82 MutexImpl* m_global_mutex_impl = nullptr;
83 bool m_use_legacy_barrier = false;
84};
85
86/*---------------------------------------------------------------------------*/
87/*---------------------------------------------------------------------------*/
88
89namespace
90{
91 void* _StdStartFunc(void* f)
92 {
93 IFunctor* ff = static_cast<IFunctor*>(f);
94 ff->executeFunctor();
95 return nullptr;
96 }
97} // namespace
98
99/*---------------------------------------------------------------------------*/
100/*---------------------------------------------------------------------------*/
101
102/*!
103 * \brief Implementation of a barrier.
104 *
105 * This implementation was used before C++20 support when the
106 * std::barrier class did not exist.
107 */
109: public IThreadBarrier
110{
111 public:
112
113 void init(Integer nb_thread) override
114 {
115 m_nb_thread = nb_thread;
116 m_current_reached = 0;
117 }
118
119 void destroy() override
120 {
121 m_nb_thread = 0;
122 m_current_reached = 0;
123 delete this;
124 }
125
126 void wait() override
127 {
128 std::unique_lock<std::mutex> lk(m_wait_mutex);
129 ++m_current_reached;
130 Int32 generation = m_generation;
131 //cout << "ADD BARRIER N=" << m_current_reached << '\n';
132 if (m_current_reached == m_nb_thread) {
133 ++m_generation;
134 m_current_reached = 0;
135 //cout << "BROADCAST BARRIER N=" << m_current_reached << '\n';
136 lk.unlock();
137 m_wait.notify_all();
138 }
139 while (generation == m_generation)
140 m_wait.wait(lk);
141 }
142
143 private:
144
145 std::mutex m_wait_mutex;
146 std::condition_variable m_wait;
147 Integer m_nb_thread = 0;
148 Integer m_current_reached = 0;
149 Int32 m_generation = 0;
150};
151
152/*---------------------------------------------------------------------------*/
153/*---------------------------------------------------------------------------*/
154
155/*!
156 * \brief Implementation of a barrier using std::barrier.
157 */
159: public IThreadBarrier
160{
161 class NullFunc
162 {
163 public:
164
165 void operator()() const noexcept { /* Nothing to do */ }
166 };
167
168 public:
169
170 ~StdThreadBarrier() override { delete m_barrier; }
171
172 public:
173
174 void init(Integer nb_thread) override
175 {
176 m_barrier = new std::barrier<NullFunc>(nb_thread);
177 }
178
179 void destroy() override
180 {
181 delete this;
182 }
183
184 void wait() override
185 {
186 ARCCORE_CHECK_POINTER(m_barrier);
187 m_barrier->arrive_and_wait();
188 }
189
190 private:
191
192 std::barrier<NullFunc>* m_barrier = nullptr;
193};
194
195/*---------------------------------------------------------------------------*/
196/*---------------------------------------------------------------------------*/
197
198StdThreadImplementation::
199StdThreadImplementation(bool use_legacy_barrier)
200: m_use_legacy_barrier(use_legacy_barrier)
201{
202}
203
204StdThreadImplementation::
205~StdThreadImplementation()
206{
207 GlobalMutex::destroy();
208 if (m_global_mutex_impl)
209 destroyMutex(m_global_mutex_impl);
210}
211
212void StdThreadImplementation::
213initialize()
214{
215 m_global_mutex_impl = createMutex();
216 GlobalMutex::init(m_global_mutex_impl);
217}
218
219ThreadImpl* StdThreadImplementation::
220createThread(IFunctor* f)
221{
222 return reinterpret_cast<ThreadImpl*>(new std::thread(&_StdStartFunc, f));
223}
224
225void StdThreadImplementation::
226joinThread(ThreadImpl* t)
227{
228 std::thread* tt = reinterpret_cast<std::thread*>(t);
229 tt->join();
230}
231
232void StdThreadImplementation::
233destroyThread(ThreadImpl* t)
234{
235 std::thread* tt = reinterpret_cast<std::thread*>(t);
236 delete tt;
237}
238
239void StdThreadImplementation::
240createSpinLock(Int64* spin_lock_addr)
241{
242 ARCCORE_THROW(NotSupportedException, "Spin lock. Use std::atomic_flag instead()");
243}
244
245void StdThreadImplementation::
246lockSpinLock(Int64* spin_lock_addr, Int64* scoped_spin_lock_addr)
247{
248 ARCCORE_THROW(NotSupportedException, "Spin lock. Use std::atomic_flag instead()");
249}
250
251void StdThreadImplementation::
252unlockSpinLock(Int64* spin_lock_addr, Int64* scoped_spin_lock_addr)
253{
254 ARCCORE_THROW(NotSupportedException, "Spin lock. Use std::atomic_flag instead()");
255}
256
257MutexImpl* StdThreadImplementation::
258createMutex()
259{
260 std::mutex* m = new std::mutex();
261 return reinterpret_cast<MutexImpl*>(m);
262}
263
264void StdThreadImplementation::
265destroyMutex(MutexImpl* mutex)
266{
267 std::mutex* m = reinterpret_cast<std::mutex*>(mutex);
268 delete m;
269}
270
271void StdThreadImplementation::
272lockMutex(MutexImpl* mutex)
273{
274 std::mutex* m = reinterpret_cast<std::mutex*>(mutex);
275 m->lock();
276}
277
278void StdThreadImplementation::
279unlockMutex(MutexImpl* mutex)
280{
281 std::mutex* m = reinterpret_cast<std::mutex*>(mutex);
282 m->unlock();
283}
284
285Int64 StdThreadImplementation::
286currentThread()
287{
288 Int64 v = std::hash<std::thread::id>{}(std::this_thread::get_id());
289 return v;
290}
291
292IThreadBarrier* StdThreadImplementation::
293createBarrier()
294{
295 if (m_use_legacy_barrier)
296 return new LegacyStdThreadBarrier();
297 return new StdThreadBarrier();
298}
299
300/*---------------------------------------------------------------------------*/
301/*---------------------------------------------------------------------------*/
302
303Ref<IThreadImplementation>
304createStdThreadImplementation()
305{
307}
308
309Ref<IThreadImplementation>
310createLegacyStdThreadImplementation()
311{
313}
314
315/*---------------------------------------------------------------------------*/
316/*---------------------------------------------------------------------------*/
317
318} // namespace Arcane::Concurrency
319
320/*---------------------------------------------------------------------------*/
321/*---------------------------------------------------------------------------*/
#define ARCCORE_THROW(exception_class,...)
Macro to throw an exception with formatting.
#define ARCCORE_CHECK_POINTER(ptr)
Macro that returns the pointer ptr if it is not null or throws an exception if it is null.
#define ARCCORE_DEFINE_REFERENCE_COUNTED_INCLASS_METHODS()
Macro to define methods managing counters of references.
Management of references to a C++ class.
void init(Integer nb_thread) override
Initializes the barrier for nb_thread.
void wait() override
Blocks and waits until all threads call this method.
void destroy() override
Destroys the barrier.
Implementation of a barrier using std::barrier.
void destroy() override
Destroys the barrier.
void wait() override
Blocks and waits until all threads call this method.
void init(Integer nb_thread) override
Initializes the barrier for nb_thread.
Implementation of ITreadImplementation using the standard C++ library.
static void init(MutexImpl *p)
Initializes the global mutex. Internal to Arccore. Must be allocated by new.
Definition Mutex.cc:60
virtual void executeFunctor()=0
Executes the associated method.
Thread-safe implementation of a reference counter.
std::int64_t Int64
Signed integer type of 64 bits.
Int32 Integer
Type representing an integer.
auto makeRef(InstanceType *t) -> Ref< InstanceType >
Creates a reference on a pointer.
std::int32_t Int32
Signed integer type of 32 bits.