swoole\atomic::cmpset用于条件性更新共享整数,典型场景包括无锁状态机、乐观并发控制、一次性初始化等;其返回值为操作后当前值,需显式比较判断是否成功,参数须为≤4294967295的非负整数。

Swoole\Atomic::cmpset 不是通用赋值工具,它只在「需要条件性更新一个共享整数」时才该用。直接调用 set() 或 add() 更简单安全;滥用 cmpset() 反而容易引入逻辑漏洞或性能抖动。
什么时候必须用 cmpset?
典型场景是实现无锁状态机、乐观并发控制、一次性初始化或幂等计数器重置。比如:多个 Worker 进程竞争将某个全局标志从 0 改为 1,只允许第一个成功者生效,其余全部失败——这正是 CAS(Compare-And-Swap)的本意。
- 服务启动后首次标记「配置已加载」,避免重复解析 YAML
- 请求计数器达到阈值后原子切换告警开关(如从 0→1,但不允许多次触发)
- 分布式限流中判断当前窗口是否已被某进程“抢占”并初始化
cmpset 的参数和返回值容易误解
cmpset($cmp_value, $new_value) 的返回值不是布尔值,而是 操作后的当前值(即如果成功,返回 $new_value;失败则返回当前真实值,不等于 $cmp_value)。很多人误以为它返回 true/false,结果写出永远不进分支的代码。
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
- 必须显式比较返回值是否等于
$new_value,才能判断是否成功:if ($atomic->cmpset(0, 1) === 1) { /* 初始化成功 */ } -
$cmp_value和$new_value必须是小于 232 的非负整数(即 ≤ 4294967295),超出会截断或触发未定义行为 - 底层依赖 CPU 的
cmpxchg指令,不跨平台兼容问题,但在 x86/x64/Linux 上稳定
和 Atomic 其他方法的协作边界
cmpset 和 get()、add() 不是互斥替代关系,而是分工明确:前者管「条件写」,后者管「无条件读/改」。混用时要注意时序漏洞。
- 不要写
if ($atomic->get() === 0) { $atomic->cmpset(0, 1); }—— 这中间存在竞态窗口,get()和cmpset()不是原子组合 - 正确做法是只用一次
cmpset(0, 1)并检查返回值 - 若需「先读再按条件加」,应改用
Table+ 行锁,或Lock包裹临界区,Atomic本身不提供读-改-写复合操作
真正难的是设计清楚「什么状态需要靠 cmpset 保护」——多数时候你其实只需要 incr() 或 set()。一旦开始琢磨 cmpset,就得同步考虑失败路径怎么兜底、重试要不要加延迟、以及是否暴露了架构上本该由更高层(比如 Table 或 Redis)承担的状态协调责任。










