Arcane  v4.1.5.0
Documentation utilisateur
Chargement...
Recherche...
Aucune correspondance
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/* Implémentation des threads utilisant la bibliothèque standard C++. */
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 * \brief Implémentation de ITreadImplementation avec la bibliothèque standard C++.
39 */
40class ARCCORE_CONCURRENCY_EXPORT StdThreadImplementation
43{
45
46 public:
47
48 explicit StdThreadImplementation(bool use_legacy_barrier);
49 ~StdThreadImplementation() override;
50
51 public:
52
53 void initialize() override;
54
55 public:
56
57 ThreadImpl* createThread(IFunctor* f) override;
58 void joinThread(ThreadImpl* t) override;
59 void destroyThread(ThreadImpl* t) override;
60
61 void createSpinLock(Int64* spin_lock_addr) override;
62 void lockSpinLock(Int64* spin_lock_addr, Int64* scoped_spin_lock_addr) override;
63 void unlockSpinLock(Int64* spin_lock_addr, Int64* scoped_spin_lock_addr) override;
64
65 MutexImpl* createMutex() override;
66 void destroyMutex(MutexImpl*) override;
67 void lockMutex(MutexImpl* mutex) override;
68 void unlockMutex(MutexImpl* mutex) override;
69
70 Int64 currentThread() override;
71
72 IThreadBarrier* createBarrier() override;
73
74 public:
75
76 void addReference() override { ReferenceCounterImpl::addReference(); }
77 void removeReference() override { ReferenceCounterImpl::removeReference(); }
78
79 private:
80
81 MutexImpl* m_global_mutex_impl = nullptr;
82 bool m_use_legacy_barrier = false;
83};
84
85/*---------------------------------------------------------------------------*/
86/*---------------------------------------------------------------------------*/
87
88namespace
89{
90 void* _StdStartFunc(void* f)
91 {
92 IFunctor* ff = static_cast<IFunctor*>(f);
93 ff->executeFunctor();
94 return nullptr;
95 }
96} // namespace
97
98/*---------------------------------------------------------------------------*/
99/*---------------------------------------------------------------------------*/
100/*!
101 * \brief Implémentation d'une barrière.
102 *
103 * Cette implémentation etait utilisée avant le support du C++20 lorsque la
104 * classe std::barrier n'existait pas.
105 */
107: public IThreadBarrier
108{
109 public:
110
111 void init(Integer nb_thread) override
112 {
113 m_nb_thread = nb_thread;
114 m_current_reached = 0;
115 }
116
117 void destroy() override
118 {
119 m_nb_thread = 0;
120 m_current_reached = 0;
121 delete this;
122 }
123
124 void wait() override
125 {
126 std::unique_lock<std::mutex> lk(m_wait_mutex);
127 ++m_current_reached;
128 Int32 generation = m_generation;
129 //cout << "ADD BARRIER N=" << m_current_reached << '\n';
130 if (m_current_reached == m_nb_thread) {
131 ++m_generation;
132 m_current_reached = 0;
133 //cout << "BROADCAST BARRIER N=" << m_current_reached << '\n';
134 lk.unlock();
135 m_wait.notify_all();
136 }
137 while (generation == m_generation)
138 m_wait.wait(lk);
139 }
140
141 private:
142
143 std::mutex m_wait_mutex;
144 std::condition_variable m_wait;
145 Integer m_nb_thread = 0;
146 Integer m_current_reached = 0;
147 Int32 m_generation = 0;
148};
149
150/*---------------------------------------------------------------------------*/
151/*---------------------------------------------------------------------------*/
152/*!
153 * \brief Implémentation d'une barrière via std::barrier.
154 */
156: public IThreadBarrier
157{
158 class NullFunc
159 {
160 public:
161
162 void operator()() const noexcept { /* Nothing to do */ }
163 };
164
165 public:
166
167 ~StdThreadBarrier() override { delete m_barrier; }
168
169 public:
170
171 void init(Integer nb_thread) override
172 {
173 m_barrier = new std::barrier<NullFunc>(nb_thread);
174 }
175
176 void destroy() override
177 {
178 delete this;
179 }
180
181 void wait() override
182 {
183 ARCCORE_CHECK_POINTER(m_barrier);
184 m_barrier->arrive_and_wait();
185 }
186
187 private:
188
189 std::barrier<NullFunc>* m_barrier = nullptr;
190};
191
192/*---------------------------------------------------------------------------*/
193/*---------------------------------------------------------------------------*/
194
195StdThreadImplementation::
196StdThreadImplementation(bool use_legacy_barrier)
197: m_use_legacy_barrier(use_legacy_barrier)
198{
199}
200
201StdThreadImplementation::
202~StdThreadImplementation()
203{
204 GlobalMutex::destroy();
205 if (m_global_mutex_impl)
206 destroyMutex(m_global_mutex_impl);
207}
208
209void StdThreadImplementation::
210initialize()
211{
212 m_global_mutex_impl = createMutex();
213 GlobalMutex::init(m_global_mutex_impl);
214}
215
216ThreadImpl* StdThreadImplementation::
217createThread(IFunctor* f)
218{
219 return reinterpret_cast<ThreadImpl*>(new std::thread(&_StdStartFunc, f));
220}
221
222void StdThreadImplementation::
223joinThread(ThreadImpl* t)
224{
225 std::thread* tt = reinterpret_cast<std::thread*>(t);
226 tt->join();
227}
228
229void StdThreadImplementation::
230destroyThread(ThreadImpl* t)
231{
232 std::thread* tt = reinterpret_cast<std::thread*>(t);
233 delete tt;
234}
235
236void StdThreadImplementation::
237createSpinLock(Int64* spin_lock_addr)
238{
239 ARCCORE_THROW(NotSupportedException, "Spin lock. Use std::atomic_flag instead()");
240}
241
242void StdThreadImplementation::
243lockSpinLock(Int64* spin_lock_addr, Int64* scoped_spin_lock_addr)
244{
245 ARCCORE_THROW(NotSupportedException, "Spin lock. Use std::atomic_flag instead()");
246}
247
248void StdThreadImplementation::
249unlockSpinLock(Int64* spin_lock_addr, Int64* scoped_spin_lock_addr)
250{
251 ARCCORE_THROW(NotSupportedException, "Spin lock. Use std::atomic_flag instead()");
252}
253
254MutexImpl* StdThreadImplementation::
255createMutex()
256{
257 std::mutex* m = new std::mutex();
258 return reinterpret_cast<MutexImpl*>(m);
259}
260
261void StdThreadImplementation::
262destroyMutex(MutexImpl* mutex)
263{
264 std::mutex* m = reinterpret_cast<std::mutex*>(mutex);
265 delete m;
266}
267
268void StdThreadImplementation::
269lockMutex(MutexImpl* mutex)
270{
271 std::mutex* m = reinterpret_cast<std::mutex*>(mutex);
272 m->lock();
273}
274
275void StdThreadImplementation::
276unlockMutex(MutexImpl* mutex)
277{
278 std::mutex* m = reinterpret_cast<std::mutex*>(mutex);
279 m->unlock();
280}
281
282Int64 StdThreadImplementation::
283currentThread()
284{
285 Int64 v = std::hash<std::thread::id>{}(std::this_thread::get_id());
286 return v;
287}
288
289IThreadBarrier* StdThreadImplementation::
290createBarrier()
291{
292 if (m_use_legacy_barrier)
293 return new LegacyStdThreadBarrier();
294 return new StdThreadBarrier();
295}
296
297/*---------------------------------------------------------------------------*/
298/*---------------------------------------------------------------------------*/
299
300Ref<IThreadImplementation>
301createStdThreadImplementation()
302{
304}
305
306Ref<IThreadImplementation>
307createLegacyStdThreadImplementation()
308{
310}
311
312/*---------------------------------------------------------------------------*/
313/*---------------------------------------------------------------------------*/
314
315} // namespace Arccore::Concurrency
316
317/*---------------------------------------------------------------------------*/
318/*---------------------------------------------------------------------------*/
#define ARCCORE_THROW(exception_class,...)
Macro pour envoyer une exception avec formattage.
#define ARCCORE_CHECK_POINTER(ptr)
Macro retournant le pointeur ptr s'il est non nul ou lancant une exception s'il est nul.
#define ARCCORE_DEFINE_REFERENCE_COUNTED_INCLASS_METHODS()
Macro pour définir les méthodes gérant les compteurs de référence.
Gestion des références à une classe C++.
void init(Integer nb_thread) override
Initialise la barrière pour nb_thread.
void wait() override
Bloque et attend que tous les threads appellent cette méthode.
void destroy() override
Détruit la barrière.
Implémentation d'une barrière via std::barrier.
void destroy() override
Détruit la barrière.
void wait() override
Bloque et attend que tous les threads appellent cette méthode.
void init(Integer nb_thread) override
Initialise la barrière pour nb_thread.
Implémentation de ITreadImplementation avec la bibliothèque standard C++.
static void init(MutexImpl *p)
Initialise le mutex global. Interne a Arccore. Doit être alloué par new.
Definition Mutex.cc:60
virtual void executeFunctor()=0
Exécute la méthode associé
Interface d'un service implémentant le support des threads.
Implémentation thread-safe d'un compteur de référence.
std::int64_t Int64
Type entier signé sur 64 bits.
Int32 Integer
Type représentant un entier.
auto makeRef(InstanceType *t) -> Ref< InstanceType >
Créé une référence sur un pointeur.
std::int32_t Int32
Type entier signé sur 32 bits.