Arcane  v4.1.7.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
TestConcurrency.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#include <gtest/gtest.h>
8
9#include "arccore/base/PlatformUtils.h"
10#include "arccore/base/Functor.h"
11#include "arccore/base/Ref.h"
12
13#include "arccore/concurrency/internal/ConcurrencyGlobalInternal.h"
14#include "arccore/concurrency/SpinLock.h"
15#include "arccore/concurrency/Mutex.h"
16#include "arccore/concurrency/IThreadBarrier.h"
17
18using namespace Arcane;
19
20/*---------------------------------------------------------------------------*/
21/*---------------------------------------------------------------------------*/
22
23class MyThread
24{
25 public:
26
27 MyThread() = default;
28 explicit MyThread(IFunctor* f)
29 {
30 create(f);
31 }
32 ~MyThread()
33 {
34 if (m_thread)
35 Concurrency::getThreadImplementation()->destroyThread(m_thread);
36 }
37 void create(IFunctor* f)
38 {
39 m_functor = f;
40 m_thread = Concurrency::getThreadImplementation()->createThread(f);
41 }
42 void join()
43 {
44 Concurrency::getThreadImplementation()->joinThread(m_thread);
45 }
46
47 public:
48
49 IFunctor* m_functor = nullptr;
50 ThreadImpl* m_thread = nullptr;
51};
52
53/*---------------------------------------------------------------------------*/
54/*---------------------------------------------------------------------------*/
55
56class TestSpinLock1
57{
58 public:
59
60 TestSpinLock1()
61 {
62 }
63
64 explicit TestSpinLock1(SpinLock::eMode mode)
65 : m_lock(mode)
66 {
67 }
68
69 void exec()
70 {
72 const Int32 nb_iter = 70;
73 const Int32 nb_thread = 10;
74 for (Integer i = 0; i < nb_iter; ++i) {
75 FunctorT<TestSpinLock1> f1(this, &TestSpinLock1::_F1);
76 std::vector<MyThread> threads(nb_thread);
77 for (Integer j = 0; j < nb_thread; ++j)
78 threads[j].create(&f1);
79 for (Integer j = 0; j < nb_thread; ++j)
80 threads[j].join();
81 }
83 std::cout << "Test1 spin_time=" << (v2 - v1) << " count2=" << m_count2 << " count3=" << m_count3 << "\n";
84 Int64 expected_count3 = nb_iter * m_nb_sub_iter * nb_thread;
85 Int64 expected_count2 = 10 * expected_count3 + (expected_count3 * (expected_count3 + 1)) / 2;
86 std::cout << " expected_count2=" << expected_count2 << " expected_count3=" << expected_count3 << "\n";
87 ASSERT_EQ(m_count2, expected_count2);
88 ASSERT_EQ(m_count3, expected_count3);
89 }
90 void _F1()
91 {
92 for (Int32 i = 0; i < m_nb_sub_iter; ++i) {
93 ++m_count;
94 {
95 SpinLock::ScopedLock sl(m_lock);
96 ++m_count3;
97 m_count2 += 10;
98 m_count2 += m_count3;
99 }
100 }
101 }
102 SpinLock m_lock;
103 std::atomic<Int64> m_count = 0;
104 Int64 m_count2 = 0;
105 Int64 m_count3 = 0;
106 Int32 m_nb_sub_iter = 1000;
107};
108
109/*---------------------------------------------------------------------------*/
110/*---------------------------------------------------------------------------*/
111
112class TestMutexLock1
113{
114 public:
115
116 TestMutexLock1()
117 : m_thread_implementation(Concurrency::getThreadImplementation())
118 {
119 }
120
121 void exec()
122 {
124 const Int32 nb_iter = 70;
125 const Int32 nb_thread = 10;
126 m_thread_barrier = m_thread_implementation->createBarrier();
127 m_thread_barrier->init(nb_thread);
128 for (Integer i = 0; i < nb_iter; ++i) {
129 FunctorT<TestMutexLock1> f1(this, &TestMutexLock1::_F1);
130 std::vector<MyThread> threads(nb_thread);
131 for (Integer j = 0; j < nb_thread; ++j)
132 threads[j].create(&f1);
133 for (Integer j = 0; j < nb_thread; ++j)
134 threads[j].join();
135 m_do_print_id = false;
136 }
138 Int64 nb_sub_iter = m_nb_sub_iter;
139 std::cout << "Test1 spin_time=" << (v2 - v1) << " count2=" << m_count2 << " count3=" << m_count3 << "\n";
140 Int64 i64_nb_thread = nb_thread;
141 Int64 expected_count3 = nb_iter * nb_sub_iter * i64_nb_thread;
142 Int64 expected_count2 = 10 * expected_count3 + (expected_count3 * (expected_count3 + 1)) / 2;
143 std::cout << " expected_count2=" << expected_count2 << " expected_count3=" << expected_count3 << "\n";
144 ASSERT_EQ(m_count2, expected_count2);
145 ASSERT_EQ(m_count3, expected_count3);
146 m_thread_barrier->destroy();
147 }
148 void _F1()
149 {
150 for (Int32 i = 0; i < m_nb_sub_iter; ++i) {
151 ++m_count;
152 {
153 Mutex::ScopedLock sl(m_mutex);
154 ++m_count3;
155 m_count2 += 10;
156 m_count2 += m_count3;
157 }
158 }
159 m_thread_barrier->wait();
160 if (m_do_print_id) {
161 std::ostringstream ostr;
162 ostr << "THREAD_ID=" << m_thread_implementation->currentThread() << "\n";
163 std::cout << ostr.str();
164 }
165 }
166 IThreadImplementation* m_thread_implementation = nullptr;
167 Mutex m_mutex;
168 IThreadBarrier* m_thread_barrier = nullptr;
169 std::atomic<Int64> m_count = 0;
170 Int64 m_count2 = 0;
171 Int64 m_count3 = 0;
172 Int32 m_nb_sub_iter = 1000;
173 bool m_do_print_id = true;
174};
175
176namespace
177{
178void _doSpinLock()
179{
180
181 {
182 TestSpinLock1 test1;
183 test1.exec();
184 }
185 {
187 test2.exec();
188 }
189 {
191 test3.exec();
192 }
193}
194void _doMutexLock()
195{
196
197 {
198 TestMutexLock1 test1;
199 test1.exec();
200 }
201}
202} // namespace
203
204TEST(Concurrency, GlibSpinLock)
205{
206 Ref<IThreadImplementation> timpl(Concurrency::createGlibThreadImplementation());
207 Concurrency::setThreadImplementation(timpl.get());
208 _doSpinLock();
209 Concurrency::setThreadImplementation(nullptr);
210}
211
212TEST(Concurrency, StdSpinLock)
213{
214 Ref<IThreadImplementation> timpl(Concurrency::createStdThreadImplementation());
215 Concurrency::setThreadImplementation(timpl.get());
216 _doSpinLock();
217 Concurrency::setThreadImplementation(nullptr);
218}
219
220TEST(Concurrency, GlibMutexLock)
221{
222 Ref<IThreadImplementation> timpl(Concurrency::createGlibThreadImplementation());
223 Concurrency::setThreadImplementation(timpl.get());
224 _doMutexLock();
225 Concurrency::setThreadImplementation(nullptr);
226}
227
228TEST(Concurrency, StdMutexLock)
229{
230 Ref<IThreadImplementation> timpl(Concurrency::createStdThreadImplementation());
231 Concurrency::setThreadImplementation(timpl.get());
232 _doMutexLock();
233 Concurrency::setThreadImplementation(nullptr);
234}
235
236TEST(Concurrency, LegacyStdMutexLock)
237{
238 Ref<IThreadImplementation> timpl(Concurrency::createLegacyStdThreadImplementation());
239 Concurrency::setThreadImplementation(timpl.get());
240 _doMutexLock();
241 Concurrency::setThreadImplementation(nullptr);
242}
243
244/*---------------------------------------------------------------------------*/
245/*---------------------------------------------------------------------------*/
Gestion des références à une classe C++.
Functor associé à une méthode d'une classe T.
Interface d'un service implémentant le support des threads.
Référence à une instance.
eMode
Mode du spinlock. Le défaut est 'Auto'.
ARCCORE_BASE_EXPORT Real getRealTime()
Temps Real utilisé en secondes.
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
std::int64_t Int64
Type entier signé sur 64 bits.
Int32 Integer
Type représentant un entier.
double Real
Type représentant un réel.
std::int32_t Int32
Type entier signé sur 32 bits.