多线程环境下按count值创建删除文件的无锁实现方案咨询
结论
你当前基于全局锁的实现是完全符合需求的正确方案,不会出现重复创建文件、删除不存在文件的问题。同时也存在性能更优的无锁实现方案,不需要加锁即可满足所有要求。
无锁实现方案
利用原子比较交换(CAS, Compare And Swap)操作即可实现无锁版本,核心思路是只有成功完成count状态跃迁的线程才有权执行文件操作:
- 只有将count从0原子修改为1的线程,才负责创建文件
- 只有将count从1原子修改为0的线程,才负责删除文件
以下是实现代码(不同编程语言可替换为对应标准库的原子操作接口):
// count定义为支持原子操作的整型,比如C#的volatile int、C++的std::atomic<int> volatile int count = 0; void Add() { while (true) { int cur = Volatile.Read(ref count); if (cur > 0) { // count已经大于0,不需要创建文件,直接原子加1即可 if (Interlocked.CompareExchange(ref count, cur + 1, cur) == cur) { return; } } else // cur == 0 { // 尝试原子把count从0改成1,仅有一个线程能操作成功 if (Interlocked.CompareExchange(ref count, 1, 0) == 0) { // 只有CAS成功的线程才创建文件,不会出现重复创建 create_the_file(); return; } } // CAS失败说明count被其他线程修改,重新循环读取最新值重试 } } void Remove() { while (true) { int cur = Volatile.Read(ref count); if (cur > 1) { // count大于1,减完之后不需要删除文件,直接原子减1 if (Interlocked.CompareExchange(ref count, cur - 1, cur) == cur) { return; } } else // cur == 1 { // 尝试原子把count从1改成0,仅有一个线程能操作成功 if (Interlocked.CompareExchange(ref count, 0, 1) == 1) { // 只有CAS成功的线程才删除文件,不会删除不存在的文件 remove_the_file(); return; } } // CAS失败重试 } }
正确性验证
- 不会重复创建文件:count从0到1的CAS操作只有一个线程能执行成功,其他线程CAS失败后重试时count已经是1,不会走到创建文件的分支
- 不会删除不存在的文件:count从1到0的CAS操作只有一个线程能执行成功,此时文件一定存在;如果业务存在count为0时非法调用Remove的情况,额外加一层count==0直接返回的判断即可
- 所有count操作都是原子的,不存在并发竞争问题
两种方案的适用场景
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 全局锁实现 | 逻辑简单易懂,不易出bug,竞争极端激烈时不会有自旋开销 | 存在锁开销,高并发下会有线程阻塞、上下文切换的额外成本 | 并发量不高,优先保障逻辑可维护性的业务场景 |
| 无锁CAS实现 | 没有锁开销,高并发下性能更好,没有线程阻塞问题 | 逻辑相对复杂,竞争极端激烈时自旋会占用一定CPU | 高并发、性能要求高的场景 |
内容的提问来源于stack exchange,提问作者oos1111
相关产品推荐
相关产品推荐

