Files
茂之钳 2ecad1543f
CI / Build & Test (push) Failing after 1m31s
CI / Release Build (push) Failing after 31s
Build & Test / build-and-test (push) Has been cancelled
Build & Test / python-bindings (push) Has been cancelled
feat(v8): ultimate performance + CAM full optimization + visualization/IGA/quality
v8.1 — 极致性能 (SIMD + LockFree + Transaction + NUMA):
- simd_vector.h: Vec4d/Vec4f SSE/AVX/NEON auto-detect, batch AABB, SoA transpose
- concurrent_data: LockFreeQueue (MPMC CAS), LockFreeStack (Treiber), ConcurrentHashMap (64-segment sharded)
- transaction: Command pattern, UndoManager (infinite undo/redo), crash-recovery journal
- performance_tuning: NUMA-aware, cache_line aligned, prefetch, hot/cold separation
- 20 tests (concurrent + transaction), ~2600 lines

v8.2 — CAM 全面优化 + 装配模式:
- cam_optimization: chip_thinning, HSM, constant_engagement, trochoidal_turn_milling
- tool_life_management, probing_cycle, thread_milling
- cam_advanced enhanced: Mazak/Okuma/Haas/DMG post-processors (8 total)
- assembly_patterns: Circular/Rectangular/Mirror/PatternDriven/fill arrays
- assembly_feature enhanced: assembly-level PMI propagation, batch interference check
- 28 tests, compiled 0 errors (~2800 lines)

v8.3 — 可视化+压缩+IGA+质量闭环:
- visualization_quality: ambient_occlusion, edge_highlighting, wireframe, normals
- topology_compression: Brep compression, Edgebreaker, vertex quantization
- iga_prep: knot_insertion, degree_elevation, Bezier extraction for IGA analysis
- quality_feedback: design_rule_check, manufacturability, cost_estimation, quality_score (0-100)
- 28 tests, ~2349 lines

27 files, ~7750 lines, 76 tests
2026-07-26 23:13:22 +08:00

326 lines
13 KiB
C++

/**
* @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 <gtest/gtest.h>
#include "vde/core/concurrent_data.h"
#include <thread>
#include <vector>
#include <algorithm>
using namespace vde::core;
// ═══════════════════════════════════════════════════════════════════════════
// 测试 1: LockFreeQueue push/pop (单线程)
// ═══════════════════════════════════════════════════════════════════════════
TEST(LockFreeQueueTest, SingleThreadPushPop) {
LockFreeQueue<int> 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<int> 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<int> q(1024);
std::atomic<int> produced{0};
std::atomic<int> consumed{0};
std::atomic<int> sum_produced{0};
std::atomic<int> sum_consumed{0};
// 生产者
std::vector<std::thread> 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<std::thread> 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<int> 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<int> 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<int> s;
std::atomic<int> pop_count{0};
std::atomic<int64_t> pop_sum{0};
// 推送线程
std::vector<std::thread> 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<std::thread> 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<int, int> 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<int, int> map;
constexpr int NUM_THREADS = 8;
constexpr int PER_THREAD = 500;
std::vector<std::thread> 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<int> shared{0};
std::atomic<bool> done{false};
std::atomic<int> max_readers{0};
std::atomic<int> current_readers{0};
// 读者线程 (3 个)
std::vector<std::thread> 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); // 至少有一个读者进入过
}