swoole_mutex基于pthread_mutex_t,默认进程内独占,设use_in_process=1可跨进程;swoole_sem基于sem_t,天生支持进程间共享,但无trylock()方法,仅阻塞lock()可用。

SWOOLE_MUTEX 和 SWOOLE_SEM 的底层行为差异
互斥锁 SWOOLE_MUTEX 基于 pthread_mutex_t,默认进程内共享;设为进程间共享需传参 use_in_process = 1,底层调用 pthread_mutexattr_setpshared(..., PTHREAD_PROCESS_SHARED)。它支持 lock()(阻塞)和 trylock()(非阻塞),适合保护临界区代码段。
信号量 SWOOLE_SEM 底层是 POSIX sem_t,创建时即支持跨进程(无需额外参数),但不提供 trylock() 方法——它的 lock() 总是阻塞,trywait() 才是非阻塞等价操作(Swoole 封装中未暴露该接口,实际调用会报错或不可用)。
这意味着:你不能对 SWOOLE_SEM 对象调用 $lock->trylock(),否则抛出 Fatal error: Uncaught Error: Call to undefined method Swoole\Lock::trylock()。
什么时候该用 SWOOLE_FILELOCK 而不是 SWOOLE_SEM
当你要同步的是「对某个具体文件的读写」,比如多个 Worker 同时追加日志到 /tmp/app.log,直接用 SWOOLE_FILELOCK 最自然。它本质是 flock() 封装,锁粒度绑定到文件 inode,不需要提前初始化共享内存或信号量资源。
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
SWOOLE_SEM 更适合资源计数类场景,例如限制最多 5 个进程同时执行某类任务:sem_wait() 相当于“取号”,sem_post() 是“还号”。但它不感知文件路径,也不保证文件内容一致性。
常见误用:
- 用
SWOOLE_SEM去防止两个进程同时写同一个文件 → 错,它不锁定文件,只控制计数 - 用
SWOOLE_FILELOCK控制数据库连接池大小 → 错,文件锁无法跨机器、不适用于抽象资源
SWOOLE_RWLOCK 和 SWOOLE_MUTEX 在多读少写场景下的取舍
如果你的临界区读操作远多于写操作(如缓存配置加载、白名单校验),SWOOLE_RWLOCK 允许多个读线程/进程并发进入,仅写操作互斥。而 SWOOLE_MUTEX 不分读写,一律串行。
但注意两点:
-
SWOOLE_RWLOCK不支持trylock_rd()以外的读尝试方式,且该方法在某些旧版 glibc 中可能不可靠 - 它比
SWOOLE_MUTEX多一次系统调用开销,高并发纯写场景下反而更慢 - PHP 层没有封装
lock_rd()/unlock_rd()的易用接口,需手动调用$lock->lock()(写锁)或$lock->trylock()(读锁?不准确),实际使用容易混淆
为什么不能在 onReceive 回调里 new Swoole\Lock
每次 new Swoole\Lock(...) 都会申请一块底层 GlobalMemory,而 onReceive 是每请求触发一次,若在此处创建锁,会导致内存持续增长,最终 OOM。这不是 PHP 变量生命周期问题,而是 Swoole 内核级内存泄漏。
正确做法:
- 在 Server 启动前(如
onStart)或 Worker 进程启动时(onWorkerStart)单次创建并复用 - 确保锁对象生命周期覆盖所有需要它的子进程/协程,不要在短生命周期上下文中反复 new
- 用完后显式调用
unset($lock),触发free()回调释放底层资源
最容易被忽略的是:即使你用了 SWOOLE_FILELOCK 并传了文件路径,只要在 onReceive 里 new,一样泄漏——类型不影响这个规则。










