NOTE

4.2 Lock-Free Queue

基于 CAS 的无锁队列历史实现记录,以及安全内存回收边界。

Data Structures & Algorithms更新于 约 1 分钟读完historical

这是历史学习笔记,可能存在过时或不完整的理解。

1. 什么是LockFreeQueue

基于无锁(lock-free)思路实现的线程安全队列,通常依赖 CAS 等原子操作协调并发更新。

“lock-free”描述的是系统整体的进展保证,不表示没有任何重试,也不表示在所有负载下都一定比互斥锁更快。

2. 为什么需要LockFreeQueue

原笔记从“悲观锁 vs 乐观并发”的角度理解它:当锁竞争和线程阻塞成本成为瓶颈时,可以考虑用原子操作和重试避免持有一把覆盖整个队列的互斥锁。

是否值得使用仍然要通过实际竞争程度、延迟和吞吐量验证。

3. 如何实现LockFreeQueue

原笔记记录的核心思路是:

死循环 + CAS + 单向链表

下面保留原来的入队/出队代码形态,作为历史学习示意。它没有完整展示现代 C/C++ 原子类型、内存序和安全内存回收,因此不能直接作为生产级 MPMC 队列实现

  1. 入队
bool LockFreeQueue::enqueue(int val)
{
    QueueNode* cur_node;
    QueueNode* add_node = new QueueNode(val);
    while (1) {
        cur_node = tail;
        if (__sync_bool_compare_and_swap(&(cur_node->next), NULL, add_node)) {
            break;
        }
        else {
            __sync_bool_compare_and_swap(&tail, cur_node, cur_node->next);
        }
    }
    __sync_bool_compare_and_swap(&tail, cur_node, add_node);
    return 1;
}
  1. 出队
int LockFreeQueue::dequeue()
{
    QueueNode* cur_node;
    int        val;
    while (1) {
        cur_node = head;
        if (cur_node->next == NULL) {
            return -1;
        }

        if (__sync_bool_compare_and_swap(&head, cur_node, cur_node->next)) {
            break;
        }
    }
    val = cur_node->next->val;

    // 历史示例原本在这里立即释放旧 head。
    // 多线程无锁结构中,其他线程仍可能持有该节点的引用,
    // 因此需要 hazard pointer、epoch 等安全内存回收方案。
    return val;
}

这段历史代码还有两个需要注意的边界:

  • GCC 的 __sync_* 是较老的原子 builtin;现代 C/C++ 更常使用语言标准原子 API 或较新的 __atomic_*
  • 节点释放不能像普通单线程链表一样在出队成功后立即处理,必须保证没有其他并发线程仍在访问旧节点。

4. 参考

正在加载有帮助数量