2ecad1543f
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
586 lines
19 KiB
C++
586 lines
19 KiB
C++
#pragma once
|
||
/**
|
||
* @file concurrent_data.h
|
||
* @brief 极致性能 — 无锁并发数据结构
|
||
*
|
||
* 提供高性能线程安全容器:
|
||
* - LockFreeQueue<T> : 无锁队列 (CAS),多生产者多消费者
|
||
* - LockFreeStack<T> : 无锁栈 (CAS),单生产者单消费者为主
|
||
* - ConcurrentHashMap<K,V>: 分段锁哈希表,读写并发
|
||
* - ReadWriteSpinLock : 读写自旋锁(读优先)
|
||
*
|
||
* @ingroup core
|
||
*/
|
||
#include <atomic>
|
||
#include <vector>
|
||
#include <memory>
|
||
#include <functional>
|
||
#include <mutex>
|
||
#include <shared_mutex>
|
||
#include <cstddef>
|
||
#include <cstdint>
|
||
#include <cstring>
|
||
#include <new>
|
||
#include <utility>
|
||
#include <type_traits>
|
||
|
||
namespace vde::core {
|
||
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
// 无锁队列 (Lock-Free Queue)
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
|
||
/// 多生产者-多消费者无锁环形队列
|
||
///
|
||
/// 基于原子 CAS 操作实现,无互斥锁,适用于高吞吐场景。
|
||
/// 内部使用 2 的幂次容量保证索引取模为位运算。
|
||
///
|
||
/// @tparam T 元素类型(必须可平凡拷贝)
|
||
///
|
||
/// @note 容量必须为 2 的幂,自动向上取整
|
||
template<typename T>
|
||
class LockFreeQueue {
|
||
static_assert(std::is_trivially_copyable_v<T>,
|
||
"LockFreeQueue requires trivially copyable types");
|
||
|
||
public:
|
||
/// 构造函数
|
||
/// @param capacity 期望容量(自动向上取整到 2 的幂,最小 8)
|
||
explicit LockFreeQueue(size_t capacity = 1024)
|
||
: mask_(next_power_of_two(std::max(capacity, size_t(8))) - 1)
|
||
{
|
||
size_t real = mask_ + 1;
|
||
buffer_ = static_cast<Element*>(
|
||
::operator new(real * sizeof(Element), std::nothrow));
|
||
// placement new 初始化
|
||
for (size_t i = 0; i < real; ++i) {
|
||
new (&buffer_[i]) Element();
|
||
}
|
||
head_.store(0, std::memory_order_relaxed);
|
||
tail_.store(0, std::memory_order_relaxed);
|
||
}
|
||
|
||
~LockFreeQueue() {
|
||
if (buffer_) {
|
||
size_t real = mask_ + 1;
|
||
for (size_t i = 0; i < real; ++i) {
|
||
buffer_[i].~Element();
|
||
}
|
||
::operator delete(buffer_);
|
||
}
|
||
}
|
||
|
||
// 禁止拷贝
|
||
LockFreeQueue(const LockFreeQueue&) = delete;
|
||
LockFreeQueue& operator=(const LockFreeQueue&) = delete;
|
||
|
||
/// 尝试入队(非阻塞)
|
||
/// @param item 要入队的元素
|
||
/// @return true 若入队成功
|
||
bool try_push(const T& item) {
|
||
size_t tail = tail_.load(std::memory_order_relaxed);
|
||
for (;;) {
|
||
size_t head = head_.load(std::memory_order_acquire);
|
||
// 满判断:tail + 1 == head (mod capacity)
|
||
if ((tail - head) >= mask_) return false;
|
||
|
||
if (tail_.compare_exchange_weak(tail, tail + 1,
|
||
std::memory_order_release, std::memory_order_relaxed)) {
|
||
// 成功分配 slot
|
||
size_t idx = tail & mask_;
|
||
buffer_[idx].data = item;
|
||
buffer_[idx].ready.store(true, std::memory_order_release);
|
||
return true;
|
||
}
|
||
// CAS 失败,tail 已更新,重试
|
||
}
|
||
}
|
||
|
||
/// 尝试移动入队
|
||
bool try_push(T&& item) {
|
||
size_t tail = tail_.load(std::memory_order_relaxed);
|
||
for (;;) {
|
||
size_t head = head_.load(std::memory_order_acquire);
|
||
if ((tail - head) >= mask_) return false;
|
||
|
||
if (tail_.compare_exchange_weak(tail, tail + 1,
|
||
std::memory_order_release, std::memory_order_relaxed)) {
|
||
size_t idx = tail & mask_;
|
||
buffer_[idx].data = std::move(item);
|
||
buffer_[idx].ready.store(true, std::memory_order_release);
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// 尝试出队(非阻塞)
|
||
/// @param item 输出参数,接收出队元素
|
||
/// @return true 若出队成功
|
||
bool try_pop(T& item) {
|
||
size_t head = head_.load(std::memory_order_relaxed);
|
||
for (;;) {
|
||
size_t tail = tail_.load(std::memory_order_acquire);
|
||
if (head == tail) return false; // 空
|
||
|
||
size_t idx = head & mask_;
|
||
if (!buffer_[idx].ready.load(std::memory_order_acquire)) {
|
||
// 生产者尚未写入完成,重试
|
||
head = head_.load(std::memory_order_relaxed);
|
||
continue;
|
||
}
|
||
|
||
if (head_.compare_exchange_weak(head, head + 1,
|
||
std::memory_order_release, std::memory_order_relaxed)) {
|
||
item = std::move(buffer_[idx].data);
|
||
buffer_[idx].ready.store(false, std::memory_order_release);
|
||
return true;
|
||
}
|
||
// CAS 失败,重试
|
||
}
|
||
}
|
||
|
||
/// 是否为空
|
||
[[nodiscard]] bool empty() const {
|
||
return head_.load(std::memory_order_acquire) ==
|
||
tail_.load(std::memory_order_acquire);
|
||
}
|
||
|
||
/// 当前元素数(近似值,并发下非精确)
|
||
[[nodiscard]] size_t size() const {
|
||
size_t h = head_.load(std::memory_order_acquire);
|
||
size_t t = tail_.load(std::memory_order_acquire);
|
||
return (t >= h) ? (t - h) : 0;
|
||
}
|
||
|
||
/// 容量
|
||
[[nodiscard]] size_t capacity() const { return mask_ + 1; }
|
||
|
||
private:
|
||
struct Element {
|
||
T data{};
|
||
std::atomic<bool> ready{false};
|
||
};
|
||
|
||
Element* buffer_;
|
||
const size_t mask_; // capacity - 1 (power of 2)
|
||
alignas(64) std::atomic<size_t> head_{0};
|
||
alignas(64) std::atomic<size_t> tail_{0};
|
||
|
||
static size_t next_power_of_two(size_t v) {
|
||
v--;
|
||
v |= v >> 1; v |= v >> 2;
|
||
v |= v >> 4; v |= v >> 8;
|
||
v |= v >> 16; v |= v >> 32;
|
||
return v + 1;
|
||
}
|
||
};
|
||
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
// 无锁栈 (Lock-Free Stack)
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
|
||
/// 无锁栈 — Treiber Stack
|
||
///
|
||
/// 基于 CAS 的单链表实现,适用于单生产者单消费者或低竞争多生产者场景。
|
||
///
|
||
/// @tparam T 元素类型
|
||
template<typename T>
|
||
class LockFreeStack {
|
||
struct Node {
|
||
T data;
|
||
Node* next;
|
||
Node(const T& d, Node* n = nullptr) : data(d), next(n) {}
|
||
Node(T&& d, Node* n = nullptr) : data(std::move(d)), next(n) {}
|
||
};
|
||
|
||
public:
|
||
LockFreeStack() : head_(nullptr) {}
|
||
|
||
~LockFreeStack() {
|
||
Node* node = head_.load(std::memory_order_relaxed);
|
||
while (node) {
|
||
Node* next = node->next;
|
||
delete node;
|
||
node = next;
|
||
}
|
||
}
|
||
|
||
LockFreeStack(const LockFreeStack&) = delete;
|
||
LockFreeStack& operator=(const LockFreeStack&) = delete;
|
||
|
||
/// 压栈
|
||
void push(const T& item) {
|
||
Node* node = new Node(item);
|
||
node->next = head_.load(std::memory_order_relaxed);
|
||
while (!head_.compare_exchange_weak(node->next, node,
|
||
std::memory_order_release, std::memory_order_relaxed)) {
|
||
// 自旋重试
|
||
}
|
||
}
|
||
|
||
/// 移动压栈
|
||
void push(T&& item) {
|
||
Node* node = new Node(std::move(item));
|
||
node->next = head_.load(std::memory_order_relaxed);
|
||
while (!head_.compare_exchange_weak(node->next, node,
|
||
std::memory_order_release, std::memory_order_relaxed)) {
|
||
// 自旋重试
|
||
}
|
||
}
|
||
|
||
/// 尝试弹栈
|
||
/// @return true 若弹栈成功
|
||
bool try_pop(T& item) {
|
||
Node* node = head_.load(std::memory_order_acquire);
|
||
while (node) {
|
||
if (head_.compare_exchange_weak(node, node->next,
|
||
std::memory_order_release, std::memory_order_relaxed)) {
|
||
item = std::move(node->data);
|
||
delete node;
|
||
return true;
|
||
}
|
||
// CAS 失败,node 已更新为新的 head,继续
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/// 是否为栈空
|
||
[[nodiscard]] bool empty() const {
|
||
return head_.load(std::memory_order_acquire) == nullptr;
|
||
}
|
||
|
||
/// 清空栈
|
||
void clear() {
|
||
Node* node = head_.exchange(nullptr, std::memory_order_acq_rel);
|
||
while (node) {
|
||
Node* next = node->next;
|
||
delete node;
|
||
node = next;
|
||
}
|
||
}
|
||
|
||
private:
|
||
std::atomic<Node*> head_;
|
||
};
|
||
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
// 分段锁哈希表 (Concurrent HashMap)
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
|
||
/// 分段锁哈希表
|
||
///
|
||
/// 将哈希表分成多个段(Segment),每段独立加锁。
|
||
/// 不同段的操作完全并行,同一段内部串行。
|
||
///
|
||
/// @tparam K 键类型
|
||
/// @tparam V 值类型
|
||
/// @tparam Hash 哈希函数(默认 std::hash<K>)
|
||
///
|
||
/// @note 段数量固定为 64(2 的幂),保证取模为位运算
|
||
template<typename K, typename V, typename Hash = std::hash<K>>
|
||
class ConcurrentHashMap {
|
||
static constexpr size_t NUM_SEGMENTS = 64;
|
||
static constexpr size_t SEGMENT_MASK = NUM_SEGMENTS - 1;
|
||
|
||
struct Entry {
|
||
K key;
|
||
V value;
|
||
Entry* next = nullptr;
|
||
Entry(const K& k, const V& v) : key(k), value(v) {}
|
||
Entry(K&& k, V&& v) : key(std::move(k)), value(std::move(v)) {}
|
||
};
|
||
|
||
struct alignas(64) Bucket {
|
||
Entry* head = nullptr;
|
||
};
|
||
|
||
struct alignas(64) Segment {
|
||
std::shared_mutex mutex;
|
||
std::vector<Bucket> buckets;
|
||
|
||
Segment() : buckets(16) {} // 初始 16 桶/段
|
||
};
|
||
|
||
public:
|
||
ConcurrentHashMap() {
|
||
for (size_t i = 0; i < NUM_SEGMENTS; ++i) {
|
||
segments_[i].store(new Segment(), std::memory_order_relaxed);
|
||
}
|
||
}
|
||
|
||
~ConcurrentHashMap() {
|
||
for (size_t i = 0; i < NUM_SEGMENTS; ++i) {
|
||
Segment* seg = segments_[i].load(std::memory_order_relaxed);
|
||
if (seg) {
|
||
for (auto& bucket : seg->buckets) {
|
||
Entry* e = bucket.head;
|
||
while (e) {
|
||
Entry* next = e->next;
|
||
delete e;
|
||
e = next;
|
||
}
|
||
}
|
||
delete seg;
|
||
}
|
||
}
|
||
}
|
||
|
||
ConcurrentHashMap(const ConcurrentHashMap&) = delete;
|
||
ConcurrentHashMap& operator=(const ConcurrentHashMap&) = delete;
|
||
|
||
/// 插入或更新
|
||
/// @param key 键
|
||
/// @param value 值
|
||
void insert(const K& key, const V& value) {
|
||
size_t seg_idx = segment_index(key);
|
||
Segment* seg = segments_[seg_idx].load(std::memory_order_acquire);
|
||
std::unique_lock lock(seg->mutex);
|
||
|
||
size_t bidx = bucket_index(key, seg->buckets.size());
|
||
Entry* e = seg->buckets[bidx].head;
|
||
while (e) {
|
||
if (e->key == key) { e->value = value; return; }
|
||
e = e->next;
|
||
}
|
||
// 插入链表头
|
||
Entry* ne = new Entry(key, value);
|
||
ne->next = seg->buckets[bidx].head;
|
||
seg->buckets[bidx].head = ne;
|
||
}
|
||
|
||
/// 移动插入
|
||
void insert(K&& key, V&& value) {
|
||
size_t seg_idx = segment_index(key);
|
||
Segment* seg = segments_[seg_idx].load(std::memory_order_acquire);
|
||
std::unique_lock lock(seg->mutex);
|
||
|
||
size_t bidx = bucket_index(key, seg->buckets.size());
|
||
Entry* e = seg->buckets[bidx].head;
|
||
while (e) {
|
||
if (e->key == key) { e->value = std::move(value); return; }
|
||
e = e->next;
|
||
}
|
||
Entry* ne = new Entry(std::move(key), std::move(value));
|
||
ne->next = seg->buckets[bidx].head;
|
||
seg->buckets[bidx].head = ne;
|
||
}
|
||
|
||
/// 查找
|
||
/// @param key 键
|
||
/// @param value 输出参数
|
||
/// @return true 若找到
|
||
[[nodiscard]] bool find(const K& key, V& value) const {
|
||
size_t seg_idx = segment_index(key);
|
||
Segment* seg = segments_[seg_idx].load(std::memory_order_acquire);
|
||
std::shared_lock lock(seg->mutex);
|
||
|
||
size_t bidx = bucket_index(key, seg->buckets.size());
|
||
Entry* e = seg->buckets[bidx].head;
|
||
while (e) {
|
||
if (e->key == key) { value = e->value; return true; }
|
||
e = e->next;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/// 检查键是否存在
|
||
[[nodiscard]] bool contains(const K& key) const {
|
||
V dummy;
|
||
return find(key, dummy);
|
||
}
|
||
|
||
/// 删除键
|
||
/// @return true 若删除成功
|
||
bool erase(const K& key) {
|
||
size_t seg_idx = segment_index(key);
|
||
Segment* seg = segments_[seg_idx].load(std::memory_order_acquire);
|
||
std::unique_lock lock(seg->mutex);
|
||
|
||
size_t bidx = bucket_index(key, seg->buckets.size());
|
||
Entry** prev = &seg->buckets[bidx].head;
|
||
Entry* e = *prev;
|
||
while (e) {
|
||
if (e->key == key) {
|
||
*prev = e->next;
|
||
delete e;
|
||
return true;
|
||
}
|
||
prev = &e->next;
|
||
e = e->next;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/// 清空
|
||
void clear() {
|
||
for (size_t i = 0; i < NUM_SEGMENTS; ++i) {
|
||
Segment* seg = segments_[i].load(std::memory_order_acquire);
|
||
std::unique_lock lock(seg->mutex);
|
||
for (auto& bucket : seg->buckets) {
|
||
Entry* e = bucket.head;
|
||
while (e) {
|
||
Entry* next = e->next;
|
||
delete e;
|
||
e = next;
|
||
}
|
||
bucket.head = nullptr;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// 总元素数(近似值,遍历所有段)
|
||
[[nodiscard]] size_t size() const {
|
||
size_t total = 0;
|
||
for (size_t i = 0; i < NUM_SEGMENTS; ++i) {
|
||
Segment* seg = segments_[i].load(std::memory_order_acquire);
|
||
std::shared_lock lock(seg->mutex);
|
||
for (auto& bucket : seg->buckets) {
|
||
Entry* e = bucket.head;
|
||
while (e) { ++total; e = e->next; }
|
||
}
|
||
}
|
||
return total;
|
||
}
|
||
|
||
private:
|
||
std::atomic<Segment*> segments_[NUM_SEGMENTS];
|
||
Hash hasher_;
|
||
|
||
size_t segment_index(const K& key) const {
|
||
return hasher_(key) & SEGMENT_MASK;
|
||
}
|
||
|
||
size_t bucket_index(const K& key, size_t num_buckets) const {
|
||
return (hasher_(key) >> 6) % num_buckets;
|
||
}
|
||
};
|
||
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
// 读写自旋锁
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
|
||
/// 读优先读写自旋锁
|
||
///
|
||
/// 多个读者可以同时持有锁;写者独占。
|
||
/// 使用原子自旋等待,适合临界区极短(< 100 ns)的场景。
|
||
///
|
||
/// @note 读者数量限制为 2^30 - 1
|
||
class ReadWriteSpinLock {
|
||
static constexpr int WRITER_BIT = 0x40000000; // bit 30
|
||
static constexpr int READER_MASK = 0x3FFFFFFF; // bits 0-29
|
||
|
||
public:
|
||
ReadWriteSpinLock() : state_(0) {}
|
||
|
||
// ── 读锁 ──
|
||
|
||
/// 获取读锁(自旋等待直到无写者)
|
||
void lock_read() {
|
||
for (int spins = 0; ; ++spins) {
|
||
int s = state_.load(std::memory_order_relaxed);
|
||
if (!(s & WRITER_BIT)) {
|
||
if (state_.compare_exchange_weak(s, s + 1,
|
||
std::memory_order_acquire, std::memory_order_relaxed)) {
|
||
return;
|
||
}
|
||
}
|
||
// 自适应退避
|
||
if (spins > 100) {
|
||
// PAUSE / YIELD
|
||
#if defined(__x86_64__) || defined(_M_X64)
|
||
__builtin_ia32_pause();
|
||
#elif defined(__aarch64__)
|
||
__asm__ volatile("yield");
|
||
#endif
|
||
}
|
||
}
|
||
}
|
||
|
||
/// 释放读锁
|
||
void unlock_read() {
|
||
state_.fetch_sub(1, std::memory_order_release);
|
||
}
|
||
|
||
// ── 写锁 ──
|
||
|
||
/// 获取写锁(自旋等待直到无读者且无写者)
|
||
void lock_write() {
|
||
for (int spins = 0; ; ++spins) {
|
||
int expected = 0;
|
||
if (state_.compare_exchange_weak(expected, WRITER_BIT,
|
||
std::memory_order_acquire, std::memory_order_relaxed)) {
|
||
return;
|
||
}
|
||
if (spins > 100) {
|
||
#if defined(__x86_64__) || defined(_M_X64)
|
||
__builtin_ia32_pause();
|
||
#elif defined(__aarch64__)
|
||
__asm__ volatile("yield");
|
||
#endif
|
||
}
|
||
}
|
||
}
|
||
|
||
/// 释放写锁
|
||
void unlock_write() {
|
||
state_.store(0, std::memory_order_release);
|
||
}
|
||
|
||
/// 尝试获取读锁(非阻塞)
|
||
[[nodiscard]] bool try_lock_read() {
|
||
int s = state_.load(std::memory_order_relaxed);
|
||
if (s & WRITER_BIT) return false;
|
||
return state_.compare_exchange_strong(s, s + 1,
|
||
std::memory_order_acquire, std::memory_order_relaxed);
|
||
}
|
||
|
||
/// 尝试获取写锁(非阻塞)
|
||
[[nodiscard]] bool try_lock_write() {
|
||
int expected = 0;
|
||
return state_.compare_exchange_strong(expected, WRITER_BIT,
|
||
std::memory_order_acquire, std::memory_order_relaxed);
|
||
}
|
||
|
||
/// 是否有写者
|
||
[[nodiscard]] bool is_write_locked() const {
|
||
return state_.load(std::memory_order_acquire) & WRITER_BIT;
|
||
}
|
||
|
||
private:
|
||
std::atomic<int> state_;
|
||
};
|
||
|
||
/// RAII 读锁守卫
|
||
class ReadLockGuard {
|
||
public:
|
||
explicit ReadLockGuard(ReadWriteSpinLock& lock) : lock_(&lock) { lock_->lock_read(); }
|
||
~ReadLockGuard() { if (lock_) lock_->unlock_read(); }
|
||
ReadLockGuard(const ReadLockGuard&) = delete;
|
||
ReadLockGuard& operator=(const ReadLockGuard&) = delete;
|
||
ReadLockGuard(ReadLockGuard&& o) noexcept : lock_(o.lock_) { o.lock_ = nullptr; }
|
||
ReadLockGuard& operator=(ReadLockGuard&& o) noexcept {
|
||
if (this != &o) { lock_ = o.lock_; o.lock_ = nullptr; }
|
||
return *this;
|
||
}
|
||
private:
|
||
ReadWriteSpinLock* lock_;
|
||
};
|
||
|
||
/// RAII 写锁守卫
|
||
class WriteLockGuard {
|
||
public:
|
||
explicit WriteLockGuard(ReadWriteSpinLock& lock) : lock_(&lock) { lock_->lock_write(); }
|
||
~WriteLockGuard() { if (lock_) lock_->unlock_write(); }
|
||
WriteLockGuard(const WriteLockGuard&) = delete;
|
||
WriteLockGuard& operator=(const WriteLockGuard&) = delete;
|
||
WriteLockGuard(WriteLockGuard&& o) noexcept : lock_(o.lock_) { o.lock_ = nullptr; }
|
||
WriteLockGuard& operator=(WriteLockGuard&& o) noexcept {
|
||
if (this != &o) { lock_ = o.lock_; o.lock_ = nullptr; }
|
||
return *this;
|
||
}
|
||
private:
|
||
ReadWriteSpinLock* lock_;
|
||
};
|
||
|
||
} // namespace vde::core
|