#include #include "pls/internal/base/thread.h" #include "pls/internal/base/spin_lock.h" #include "pls/internal/base/system_details.h" #include #include using namespace pls::internal::base; using namespace std; static bool base_tests_visited; static int base_tests_local_value_one; static vector base_tests_local_value_two; TEST_CASE("thread creation and joining", "[internal/data_structures/thread.h]") { base_tests_visited = false; thread t1{[]() { base_tests_visited = true; }}; t1.join(); REQUIRE(base_tests_visited); } TEST_CASE("thread state", "[internal/data_structures/thread.h]") { int state_one = 1; vector state_two{1, 2}; thread t1{[]() { base_tests_local_value_one = *this_thread::state(); }, &state_one}; thread t2{[]() { base_tests_local_value_two = *this_thread::state>(); }, &state_two}; t1.join(); t2.join(); REQUIRE(base_tests_local_value_one == 1); REQUIRE(base_tests_local_value_two == vector{1, 2}); } int base_tests_shared_counter; TEST_CASE("spinlock protects concurrent counter", "[internal/data_structures/spinlock.h]") { constexpr int num_iterations = 1000000; base_tests_shared_counter = 0; spin_lock lock{}; SECTION("lock can be used by itself") { thread t1{[&]() { for (int i = 0; i < num_iterations; i++) { lock.lock(); base_tests_shared_counter++; lock.unlock(); } }}; thread t2{[&]() { for (int i = 0; i < num_iterations; i++) { lock.lock(); base_tests_shared_counter--; lock.unlock(); } }}; t1.join(); t2.join(); REQUIRE(base_tests_shared_counter == 0); } SECTION("lock can be used with std::lock_guard") { thread t1{[&]() { for (int i = 0; i < num_iterations; i++) { std::lock_guard my_lock{lock}; base_tests_shared_counter++; } }}; thread t2{[&]() { for (int i = 0; i < num_iterations; i++) { std::lock_guard my_lock{lock}; base_tests_shared_counter--; } }}; t1.join(); t2.join(); REQUIRE(base_tests_shared_counter == 0); } }