Skip to content

Commit 9560b81

Browse files
committed
[utest][cpp]add cpp-atomic testcase.
1 parent 0b5d5b9 commit 9560b81

File tree

1 file changed

+271
-0
lines changed

1 file changed

+271
-0
lines changed
Lines changed: 271 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
1+
/*
2+
* Copyright (c) 2006-2025, RT-Thread Development Team
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*
6+
* Change Logs:
7+
* Date Author Notes
8+
* 2025-09-19 Rbb666 the first version
9+
*/
10+
11+
#include <rtthread.h>
12+
#include "utest.h"
13+
#include <thread>
14+
#include <atomic>
15+
#include <cstdint>
16+
17+
/**
18+
* @brief Test load and store operations for int32_t atomic variables in multi-threaded environment.
19+
* Verifies atomicity by performing increment and decrement operations concurrently.
20+
*/
21+
static void test_atomic_load_store_int32(void)
22+
{
23+
constexpr int kRound = 10000000;
24+
std::atomic<int32_t> thread_count(0);
25+
std::atomic<int32_t> count(100);
26+
uassert_int_equal(count.load(), 100);
27+
28+
auto func1 = [&]() mutable {
29+
for (int i = 0; i < kRound; ++i)
30+
{
31+
++count;
32+
}
33+
++thread_count;
34+
};
35+
36+
auto func2 = [&]() mutable {
37+
for (int i = 0; i < kRound; ++i)
38+
{
39+
--count;
40+
}
41+
++thread_count;
42+
};
43+
44+
std::thread t1(func1);
45+
std::thread t2(func2);
46+
t1.join();
47+
t2.join();
48+
49+
uassert_int_equal(count.load(), 100);
50+
uassert_int_equal(thread_count.load(), 2);
51+
}
52+
53+
/**
54+
* @brief Test load and store operations for int64_t atomic variables in multi-threaded environment.
55+
* Verifies atomicity by performing increment and decrement operations concurrently.
56+
*/
57+
static void test_atomic_load_store_int64(void)
58+
{
59+
constexpr int kRound = 10000000;
60+
std::atomic<int64_t> thread_count(0);
61+
std::atomic<int64_t> count(100);
62+
uassert_int_equal(count.load(), 100);
63+
64+
auto func1 = [&]() mutable {
65+
for (int i = 0; i < kRound; ++i)
66+
{
67+
++count;
68+
}
69+
++thread_count;
70+
};
71+
72+
auto func2 = [&]() mutable {
73+
for (int i = 0; i < kRound; ++i)
74+
{
75+
--count;
76+
}
77+
++thread_count;
78+
};
79+
80+
std::thread t1(func1);
81+
std::thread t2(func2);
82+
t1.join();
83+
t2.join();
84+
85+
uassert_int_equal(count.load(), 100);
86+
uassert_int_equal(thread_count.load(), 2);
87+
}
88+
89+
/**
90+
* @brief Test basic atomic operations for int32_t, including load, store, fetch_add, fetch_sub,
91+
* fetch_and, fetch_or, fetch_xor, exchange, and compare_exchange_strong.
92+
*/
93+
static void test_atomic_basic_int32(void)
94+
{
95+
std::atomic<int32_t> val;
96+
val = 10;
97+
uassert_int_equal(val.load(), 10);
98+
99+
val++;
100+
uassert_int_equal(val.load(), 11);
101+
102+
val--;
103+
uassert_int_equal(val.load(), 10);
104+
105+
auto a = val.load();
106+
val.store(a);
107+
val.fetch_add(1);
108+
uassert_int_equal(val.load(), 11);
109+
val.fetch_sub(1);
110+
uassert_int_equal(val.load(), 10);
111+
112+
val.fetch_and(14);
113+
uassert_int_equal(val.load(), 10);
114+
115+
val.fetch_or(11); //1010
116+
uassert_int_equal(val.load(), 11);
117+
118+
val.fetch_xor(4);
119+
uassert_int_equal(val.load(), 15);
120+
121+
val.exchange(1);
122+
uassert_int_equal(val.load(), 1);
123+
124+
int32_t x = 2;
125+
int32_t y = 3;
126+
bool exchanged = val.compare_exchange_strong(x, y);
127+
uassert_false(exchanged);
128+
uassert_int_equal(val.load(), 1);
129+
uassert_int_equal(x, 1);
130+
exchanged = val.compare_exchange_strong(x, y);
131+
uassert_true(exchanged);
132+
uassert_int_equal(val.load(), 3);
133+
uassert_int_equal(x, 1);
134+
}
135+
136+
/**
137+
* @brief Test basic atomic operations for int64_t, including load, store, fetch_add, fetch_sub,
138+
* fetch_and, fetch_or, fetch_xor, exchange, and compare_exchange_strong.
139+
*/
140+
static void test_atomic_basic_int64(void)
141+
{
142+
std::atomic<int64_t> val;
143+
val = 10;
144+
uassert_int_equal(val.load(), 10);
145+
146+
val++;
147+
uassert_int_equal(val.load(), 11);
148+
149+
val--;
150+
uassert_int_equal(val.load(), 10);
151+
152+
auto a = val.load();
153+
val.store(a);
154+
val.fetch_add(1);
155+
uassert_int_equal(val.load(), 11);
156+
val.fetch_sub(1);
157+
uassert_int_equal(val.load(), 10);
158+
159+
val.fetch_and(14);
160+
uassert_int_equal(val.load(), 10);
161+
162+
val.fetch_or(11); //1010
163+
uassert_int_equal(val.load(), 11);
164+
165+
val.fetch_xor(4);
166+
uassert_int_equal(val.load(), 15);
167+
168+
val.exchange(1);
169+
uassert_int_equal(val.load(), 1);
170+
171+
int64_t x = 2;
172+
int64_t y = 3;
173+
bool exchanged = val.compare_exchange_strong(x, y);
174+
uassert_false(exchanged);
175+
uassert_int_equal(val.load(), 1);
176+
uassert_int_equal(x, 1);
177+
exchanged = val.compare_exchange_strong(x, y);
178+
uassert_true(exchanged);
179+
uassert_int_equal(val.load(), 3);
180+
uassert_int_equal(x, 1);
181+
}
182+
183+
/**
184+
* @brief Test atomic operations for bool type, including store, load, exchange, and compare_exchange_strong.
185+
*/
186+
static void test_atomic_bool(void)
187+
{
188+
std::atomic<bool> flag(false);
189+
flag.store(true);
190+
uassert_true(flag.load());
191+
flag.exchange(false);
192+
uassert_false(flag.load());
193+
bool expected = false;
194+
bool desired = true;
195+
uassert_true(flag.compare_exchange_strong(expected, desired));
196+
uassert_true(flag.load());
197+
}
198+
199+
/**
200+
* @brief Test atomic operations for pointer type (int*), including store, load, and exchange.
201+
*/
202+
static void test_atomic_pointer(void)
203+
{
204+
int a = 1, b = 2;
205+
std::atomic<int *> ptr(&a);
206+
ptr.store(&b);
207+
uassert_int_equal(*ptr.load(), 2);
208+
int *old = ptr.exchange(&a);
209+
uassert_ptr_equal(old, &b);
210+
uassert_int_equal(*ptr.load(), 1);
211+
}
212+
213+
/**
214+
* @brief Test memory ordering constraints using memory_order_release and memory_order_acquire.
215+
*/
216+
static void test_memory_order(void)
217+
{
218+
std::atomic<int> x(0);
219+
std::atomic<int> y(0);
220+
// Simple test for memory order
221+
x.store(1, std::memory_order_release);
222+
y.store(2, std::memory_order_release);
223+
uassert_int_equal(x.load(std::memory_order_acquire), 1);
224+
uassert_int_equal(y.load(std::memory_order_acquire), 2);
225+
}
226+
227+
/**
228+
* @brief Test compare_exchange_weak operation, which may fail spuriously and requires looping.
229+
*/
230+
static void test_compare_exchange_weak(void)
231+
{
232+
std::atomic<int> val(1);
233+
int expected = 1;
234+
int desired = 2;
235+
while (!val.compare_exchange_weak(expected, desired))
236+
{
237+
expected = 1; // reset
238+
}
239+
uassert_int_equal(val.load(), 2);
240+
}
241+
242+
static rt_err_t utest_tc_init(void)
243+
{
244+
return RT_EOK;
245+
}
246+
247+
static rt_err_t utest_tc_cleanup(void)
248+
{
249+
return RT_EOK;
250+
}
251+
252+
static void testcase(void)
253+
{
254+
/* Test load and store operations for int32_t atomic variables in multi-threaded environment */
255+
UTEST_UNIT_RUN(test_atomic_load_store_int32);
256+
/* Test load and store operations for int64_t atomic variables in multi-threaded environment */
257+
UTEST_UNIT_RUN(test_atomic_load_store_int64);
258+
/* Test basic atomic operations for int32_t */
259+
UTEST_UNIT_RUN(test_atomic_basic_int32);
260+
/* Test basic atomic operations for int64_t */
261+
UTEST_UNIT_RUN(test_atomic_basic_int64);
262+
/* Test atomic operations for bool type */
263+
UTEST_UNIT_RUN(test_atomic_bool);
264+
/* Test atomic operations for pointer type */
265+
UTEST_UNIT_RUN(test_atomic_pointer);
266+
/* Test memory ordering constraints */
267+
UTEST_UNIT_RUN(test_memory_order);
268+
/* Test compare_exchange_weak operation */
269+
UTEST_UNIT_RUN(test_compare_exchange_weak);
270+
}
271+
UTEST_TC_EXPORT(testcase, "testcases.cpp11.atomic_tc", utest_tc_init, utest_tc_cleanup, 10);

0 commit comments

Comments
 (0)