/** Random Delay in microseonds */ std::random_device rd; thread_local std::mt19937 gen(rd()); thread_local std::uniform_int_distribution<> dis(0, 4095);
voidunpredictableDelay(int extra = 0){ if (dis(gen) == 0) { this_thread::sleep_for(chrono::nanoseconds(2000 + extra)); } }
/** thread function for counting */ voidworker(int id){ for (int i = 0; i < increments_per_thread; ++i) { uint64_t old = counter.load(memory_order_relaxed); // 如果 load(relaxed) 不能看到当前最新值 // 那么 CAS 就会加多次,最终结果会大于 max_count while (old < max_count && !counter.compare_exchange_weak(old, old + 1, memory_order_relaxed)) { // old is updated with the current value of counter unpredictableDelay(dis(gen)); } } // cout << "Worker " << id << " done." << endl; }
/** main function */ intmain(){ for (int run = 0; run < run_times; ++run) { counter.store(0, memory_order_relaxed); cout << "Run " << run << ": "; thread threads[num_threads];
for (int i = 0; i < num_threads; ++i) { threads[i] = thread(worker, i); }
for (int i = 0; i < num_threads; ++i) { threads[i].join(); }
voidtry_advance_epoch(){ int current = global_epoch.load(std::memory_order_relaxed); for (int i = 0; i < MAX_THREADS; ++i) { if (active[i].load(std::memory_order_relaxed) && local_epoch[i].load(std::memory_order_relaxed) != current) { return; // 有线程还在旧 epoch,不能推进 } }
int next_epoch = (current + 1) % 3; global_epoch.store(next_epoch, std::memory_order_relaxed);
像 Michael-Scott 队列这种链表结构,节点被 pop 出队后地址可能被重用。如果没有安全的内存回收,另一个线 程可能 CAS 成功指向了一个“已经被释放并重用的地址”,这就是 ABA 的根源。所以 hazard pointer 或 epoch GC 是在链表队列里用来避免这种 悬空引用 + ABA 的。