基于标准C++的共享文件读写同步方案:能否防竞争、避死锁?
跨进程文件读写同步方案分析
需求背景
协调一个极少更新的写入进程(writer)和频繁读取的读取进程(reader)对共享文本文件的访问,要求完全基于标准C++实现,禁止使用Unix flock、Windows LockFile等平台特定锁功能。
现有方案实现
Reader进程代码
bool reader(const std::filesystem::path &f) { namespace fs = std::filesystem; // Check for write lock. auto write_lock_file = fs::path(f).replace_extension(".write.lock"); if (fs::exists(write_lock_file)) return false; // writer is active, aborting // Create read lock. auto read_lock_file = fs::path(f).replace_extension(".read.lock"); std::ofstream(read_lock_file).close(); // Recheck for write lock. // When the writer creates the write lock, readers that check for the write // lock will immediately abort, ensuring the writer can proceed as soon as // it's ready. if (fs::exists(write_lock_file)) { fs::remove(read_lock_file); // cleanup return false; } // READ WHAT NEEDED FROM f fs::remove(read_lock_file); return true; }
Writer进程代码
void writer(const std::filesystem::path &f) { namespace fs = std::filesystem; // Create write lock. auto write_lock_file = fs::path(f).replace_extension(".write.lock"); std::ofstream(write_lock_file).close(); // Wait for readers to finish. // After creating the write lock, the writer waits for all readers to finish // before proceeding. This ensures that existing readers are not interrupted, // but no new readers can start. auto read_lock_file = fs::path(f).replace_extension(".read.lock"); while (fs::exists(read_lock_file)) std::this_thread::sleep_for(100ms); // WRITE NEW DATA INTO f }
方案核心逻辑
读写进程通过各自的锁文件标记活动状态:
- Reader操作前先检查写锁文件,创建读锁后再次检查写锁,避免竞争;
- Writer创建写锁后,等待所有读锁消失再写入,新Reader会因检测到写锁直接放弃。
问题解答
1. 该方案能否防止读写进程间的竞争条件?
不能,存在多个核心缺陷导致竞争或功能失效:
- 多Reader场景同步逻辑错误:方案使用单个
.read.lock文件标记所有Reader状态,但每个Reader完成后都会删除该文件。当多个Reader并发读取时,第一个完成的Reader会提前删除锁文件,Writer会误判所有Reader已结束并开始写入,导致后续仍在读取的Reader与Writer发生读写数据竞争。 - Writer未清理写锁文件:现有Writer代码创建
.write.lock后未执行删除操作,写入完成后写锁会永久存在,所有后续Reader都会因检测到写锁直接返回读取失败,完全无法访问文件。 - 极端场景下的竞争窗口:虽然Reader做了两次写锁检查,但在第一次检查写锁不存在到创建读锁的时间窗口内,若Writer恰好创建写锁,Reader虽会放弃读取,但该依赖后续检查的逻辑存在极端情况下的竞争风险(不过此场景不会导致读写同时执行,仅会让Reader读取失败)。
2. 能否避免死锁或长时间阻塞?
正常流程下不会死锁,但存在长时间阻塞风险及功能失效问题:
- 死锁风险:正常执行流程中无死锁可能:
- 若Writer先创建写锁,新Reader会直接检测到写锁并放弃,不会创建读锁;已有Reader完成读取后删除读锁,Writer最终可继续执行。
- 若Reader先创建读锁,Writer创建写锁后会等待读锁消失,Reader第二次检查到写锁后会删除读锁并放弃,Writer也能继续。
(进程异常崩溃导致锁文件未清理的情况,题目说明作为单独问题考量,不在此讨论范围内)
- 长时间阻塞风险:若Writer创建写锁后,存在Reader长时间持有读锁未释放(如Reader进程挂起、读取操作耗时极长),Writer会进入无限循环等待,导致长时间阻塞。不过题目中Reader是“频繁读取”,该场景概率较低。
内容的提问来源于stack exchange,提问作者manlio
相关产品推荐
相关产品推荐

