tc_atomic.cpp 7.3 KB

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