/** * @file test_concurrent.cpp * @brief 无锁并发数据结构测试 — LockFreeQueue, LockFreeStack, * ConcurrentHashMap, ReadWriteSpinLock * * 测试项 (10项): * 1. LockFreeQueue push/pop (单线程) * 2. LockFreeQueue 空/满检测 * 3. LockFreeQueue 多生产者-多消费者 * 4. LockFreeStack push/pop (单线程) * 5. LockFreeStack 清空 * 6. LockFreeStack 多线程 * 7. ConcurrentHashMap insert/find/erase * 8. ConcurrentHashMap 多线程并发 * 9. ReadWriteSpinLock 基本锁 * 10. ReadWriteSpinLock 多读者+单写者 */ #include #include "vde/core/concurrent_data.h" #include #include #include using namespace vde::core; // ═══════════════════════════════════════════════════════════════════════════ // 测试 1: LockFreeQueue push/pop (单线程) // ═══════════════════════════════════════════════════════════════════════════ TEST(LockFreeQueueTest, SingleThreadPushPop) { LockFreeQueue q(16); EXPECT_TRUE(q.empty()); for (int i = 0; i < 10; ++i) { EXPECT_TRUE(q.try_push(i)); } EXPECT_FALSE(q.empty()); for (int i = 0; i < 10; ++i) { int val = -1; EXPECT_TRUE(q.try_pop(val)); EXPECT_EQ(val, i); } EXPECT_TRUE(q.empty()); } // ═══════════════════════════════════════════════════════════════════════════ // 测试 2: LockFreeQueue 空/满检测 // ═══════════════════════════════════════════════════════════════════════════ TEST(LockFreeQueueTest, FullAndEmptyDetection) { LockFreeQueue q(8); // 自动向上取整到 8 EXPECT_TRUE(q.empty()); EXPECT_EQ(q.capacity(), 8u); // 填满 (capacity-1 个元素,因为一个 slot 要用于区分空/满) int pushed = 0; for (int i = 0; i < 10; ++i) { if (!q.try_push(i)) break; ++pushed; } EXPECT_GT(pushed, 0); EXPECT_LE(pushed, 8); EXPECT_FALSE(q.empty()); } // ═══════════════════════════════════════════════════════════════════════════ // 测试 3: LockFreeQueue 多生产者-多消费者 // ═══════════════════════════════════════════════════════════════════════════ TEST(LockFreeQueueTest, MultiProducerMultiConsumer) { constexpr int NUM_PRODUCERS = 4; constexpr int NUM_CONSUMERS = 4; constexpr int ITEMS_PER_PRODUCER = 250; constexpr int TOTAL = NUM_PRODUCERS * ITEMS_PER_PRODUCER; LockFreeQueue q(1024); std::atomic produced{0}; std::atomic consumed{0}; std::atomic sum_produced{0}; std::atomic sum_consumed{0}; // 生产者 std::vector producers; for (int p = 0; p < NUM_PRODUCERS; ++p) { producers.emplace_back([&, p]() { for (int i = 0; i < ITEMS_PER_PRODUCER; ++i) { int val = p * 1000 + i; while (!q.try_push(val)) { std::this_thread::yield(); } sum_produced.fetch_add(val); produced.fetch_add(1); } }); } // 消费者 std::vector consumers; for (int c = 0; c < NUM_CONSUMERS; ++c) { consumers.emplace_back([&]() { int val; while (consumed.load() < TOTAL) { if (q.try_pop(val)) { sum_consumed.fetch_add(val); consumed.fetch_add(1); } else { std::this_thread::yield(); } } }); } for (auto& t : producers) t.join(); for (auto& t : consumers) t.join(); EXPECT_EQ(produced.load(), TOTAL); EXPECT_EQ(consumed.load(), TOTAL); EXPECT_EQ(sum_produced.load(), sum_consumed.load()); EXPECT_TRUE(q.empty()); } // ═══════════════════════════════════════════════════════════════════════════ // 测试 4: LockFreeStack push/pop (单线程) // ═══════════════════════════════════════════════════════════════════════════ TEST(LockFreeStackTest, SingleThreadPushPop) { LockFreeStack s; EXPECT_TRUE(s.empty()); s.push(1); s.push(2); s.push(3); EXPECT_FALSE(s.empty()); int val; EXPECT_TRUE(s.try_pop(val)); EXPECT_EQ(val, 3); EXPECT_TRUE(s.try_pop(val)); EXPECT_EQ(val, 2); EXPECT_TRUE(s.try_pop(val)); EXPECT_EQ(val, 1); EXPECT_FALSE(s.try_pop(val)); EXPECT_TRUE(s.empty()); } // ═══════════════════════════════════════════════════════════════════════════ // 测试 5: LockFreeStack 清空 // ═══════════════════════════════════════════════════════════════════════════ TEST(LockFreeStackTest, Clear) { LockFreeStack s; s.push(10); s.push(20); s.push(30); EXPECT_FALSE(s.empty()); s.clear(); EXPECT_TRUE(s.empty()); int val; EXPECT_FALSE(s.try_pop(val)); } // ═══════════════════════════════════════════════════════════════════════════ // 测试 6: LockFreeStack 多线程 // ═══════════════════════════════════════════════════════════════════════════ TEST(LockFreeStackTest, MultiThreaded) { constexpr int NUM_THREADS = 4; constexpr int PER_THREAD = 500; LockFreeStack s; std::atomic pop_count{0}; std::atomic pop_sum{0}; // 推送线程 std::vector pushers; for (int t = 0; t < NUM_THREADS; ++t) { pushers.emplace_back([&, t]() { for (int i = 0; i < PER_THREAD; ++i) { s.push(t * 1000 + i); } }); } // 等待推送完成 for (auto& t : pushers) t.join(); // 弹出线程 std::vector poppers; for (int t = 0; t < NUM_THREADS; ++t) { poppers.emplace_back([&]() { int val; while (pop_count.load() < NUM_THREADS * PER_THREAD) { if (s.try_pop(val)) { pop_sum.fetch_add(val); pop_count.fetch_add(1); } else { std::this_thread::yield(); } } }); } for (auto& t : poppers) t.join(); EXPECT_EQ(pop_count.load(), NUM_THREADS * PER_THREAD); } // ═══════════════════════════════════════════════════════════════════════════ // 测试 7: ConcurrentHashMap insert/find/erase // ═══════════════════════════════════════════════════════════════════════════ TEST(ConcurrentHashMapTest, BasicOps) { ConcurrentHashMap map; // insert map.insert(1, 100); map.insert(2, 200); map.insert(3, 300); int val; EXPECT_TRUE(map.find(1, val)); EXPECT_EQ(val, 100); EXPECT_TRUE(map.find(2, val)); EXPECT_EQ(val, 200); EXPECT_TRUE(map.contains(3)); EXPECT_FALSE(map.contains(99)); // update map.insert(1, 111); EXPECT_TRUE(map.find(1, val)); EXPECT_EQ(val, 111); // erase EXPECT_TRUE(map.erase(2)); EXPECT_FALSE(map.contains(2)); EXPECT_FALSE(map.erase(2)); // 重复删除 EXPECT_EQ(map.size(), 2u); } // ═══════════════════════════════════════════════════════════════════════════ // 测试 8: ConcurrentHashMap 多线程并发 // ═══════════════════════════════════════════════════════════════════════════ TEST(ConcurrentHashMapTest, ConcurrentInsert) { ConcurrentHashMap map; constexpr int NUM_THREADS = 8; constexpr int PER_THREAD = 500; std::vector threads; for (int t = 0; t < NUM_THREADS; ++t) { threads.emplace_back([&, t]() { for (int i = 0; i < PER_THREAD; ++i) { int key = t * PER_THREAD + i; map.insert(key, key * 10); } }); } for (auto& t : threads) t.join(); EXPECT_EQ(map.size(), size_t(NUM_THREADS * PER_THREAD)); // 验证部分键值 int val; EXPECT_TRUE(map.find(0, val)); EXPECT_EQ(val, 0); EXPECT_TRUE(map.find(500, val)); EXPECT_EQ(val, 5000); EXPECT_TRUE(map.find(3999, val)); EXPECT_EQ(val, 39990); } // ═══════════════════════════════════════════════════════════════════════════ // 测试 9: ReadWriteSpinLock 基本锁 // ═══════════════════════════════════════════════════════════════════════════ TEST(ReadWriteSpinLockTest, BasicLockUnlock) { ReadWriteSpinLock rwlock; EXPECT_FALSE(rwlock.is_write_locked()); // 写锁 rwlock.lock_write(); EXPECT_TRUE(rwlock.is_write_locked()); rwlock.unlock_write(); EXPECT_FALSE(rwlock.is_write_locked()); // 读锁 rwlock.lock_read(); EXPECT_FALSE(rwlock.is_write_locked()); // 读者不加写锁 rwlock.unlock_read(); } // ═══════════════════════════════════════════════════════════════════════════ // 测试 10: ReadWriteSpinLock 多读者+单写者 // ═══════════════════════════════════════════════════════════════════════════ TEST(ReadWriteSpinLockTest, ReadersWriter) { ReadWriteSpinLock rwlock; std::atomic shared{0}; std::atomic done{false}; std::atomic max_readers{0}; std::atomic current_readers{0}; // 读者线程 (3 个) std::vector readers; for (int i = 0; i < 3; ++i) { readers.emplace_back([&]() { while (!done.load()) { rwlock.lock_read(); int r = current_readers.fetch_add(1) + 1; int m = max_readers.load(); while (r > m) max_readers.compare_exchange_weak(m, r); EXPECT_GE(shared.load(), 0); // 读取共享数据 current_readers.fetch_sub(1); rwlock.unlock_read(); std::this_thread::yield(); } }); } // 写者线程 std::thread writer([&]() { for (int i = 0; i < 100; ++i) { rwlock.lock_write(); shared.fetch_add(1); rwlock.unlock_write(); std::this_thread::yield(); } }); writer.join(); done.store(true); for (auto& t : readers) t.join(); EXPECT_EQ(shared.load(), 100); EXPECT_GT(max_readers.load(), 0); // 至少有一个读者进入过 }