You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于指针最高16位作为标签的C++无锁队列实现疑问

并发无锁队列指针位编码问题解答

我正在实现一个并发无锁队列,打算把标签存储在指针的16个最高有效位中,参考经典无锁队列算法。但原算法的指针结构体包含独立计数变量(structure pointer_t {ptr: pointer to node_t, count: unsigned integer}),而我只能用单个指针实现,目前代码如下:

template<class P>
struct pointer_t {
    P* ptr;
    // 没有额外的uint存储标签
    P* address(){
        return (P*)(ptr & 0x0000FFFFFFFFFFFF);
    }

    uint count(){
        return ptr & 0xFFFF000000000000;
    }
};

针对提出的三个问题,解答如下:


1. 正确提取最高16位计数并转为uint

当前count()返回的是带高位掩码的指针位模式,并非真正的uint计数。需要先将指针转成标准整数类型做位运算,再提取有效计数:

#include <cstdint> // 引入uintptr_t

uint count(){
    // 先转成和指针同宽的无符号整数,右移48位把高16位移到低位,再取低16位
    return static_cast<uint>((reinterpret_cast<uintptr_t>(ptr) >> 48) & 0xFFFF);
}

注意:标准C++不允许直接对指针做位操作,必须转成uintptr_t(指针宽度的无符号整数)才是合规行为。


2. address()函数的正确性修正

当前实现存在未定义行为(直接操作指针位),正确写法需先转成uintptr_t处理,再转回指针:

#include <cstdint>

P* address(){
    auto ptr_val = reinterpret_cast<uintptr_t>(ptr);
    // 保留低48位地址,清除高16位的计数部分
    auto addr_val = ptr_val & 0x0000FFFFFFFFFFFF;
    return reinterpret_cast<P*>(addr_val);
}

x86-64用户态平台的虚拟地址确实只使用低48位,这个掩码是有效的;若在其他平台使用,需根据地址宽度调整掩码值。


3. 用位操作实现带计数递增的CAS

要实现原算法中<node, next.count+1>的原子更新,需把新节点地址和递增后的计数合并为一个指针值,步骤如下:

#include <cstdint>

// 假设已有当前的next指针结构体和新节点
pointer_t<P> next = ...;
P* new_node = ...;

// 1. 计算递增后的新计数
uint new_count = next.count() + 1;
// 2. 清除新节点地址的高16位(避免和计数冲突)
auto new_node_val = reinterpret_cast<uintptr_t>(new_node) & 0x0000FFFFFFFFFFFF;
// 3. 合并计数与地址:计数左移48位,和地址位做或运算
auto combined_val = new_node_val | (static_cast<uintptr_t>(new_count) << 48);
// 4. 转成指针类型传入CAS,完成原子更新
bool success = CAS(&tail.ptr->next, next.ptr, reinterpret_cast<P*>(combined_val));

注意:x86-64用户态地址的高16位本身就是0,无需额外处理;若平台地址范围不同,需确保地址不会占用计数位。


内容的提问来源于stack exchange,提问作者callum arul

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 22:07:34