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