GNU Linux单写多读进程场景下文件访问同步问题及代码有效性确认问询
多进程文件读写的同步问题分析
你完全是对的——这段代码绝对无法保证读进程能稳定读取到正确的TestValue,你的担忧非常合理,用命名信号量来做同步确实是解决这类跨进程访问问题的可靠方案。
先拆解下当前代码的核心问题:
- 写操作完全没有原子性:它先打开文件清空内容(写入10个空字符),关闭后再重新打开写入TestValue。这两步之间存在明显的时间窗口,读进程完全可能在间隙中读取到空内容。
- 多进程访问无同步机制:哪怕没有上述间隙,读进程也可能在写进程刚写入部分数据时就开始读取,拿到不完整的数值;如果有多个写进程同时操作,文件内容会彻底混乱。
- 小细节提醒:代码里的文件权限
0x7770建议改成八进制07770,这是Linux权限的标准写法,避免误解。
接下来聊下怎么用命名信号量修复这个问题:
命名信号量是跨进程同步的绝佳选择,它通过全局名称实现不同进程间的识别与共享,能完美解决这类竞态问题。
写进程的改造思路
- 创建/打开命名信号量,初始值设为1(相当于互斥锁)
- 调用
sem_wait()获取信号量(进入临界区,加锁) - 把两次
open/close合并成一次操作,直接定位到文件开头覆盖写入,彻底消除中间的时间间隙 - 调用
sem_post()释放信号量(退出临界区,解锁) - 不再使用信号量时记得销毁它
改造后的写进程代码示例:
#include <semaphore.h> #include <fcntl.h> #include <unistd.h> #include <cstring> #include <string> #define SEM_NAME "/test_value_sem" int wr2f(const std::string& f_name, const uint16_t TestValue) { // 创建/打开命名信号量,初始值1,权限0666 sem_t* sem = sem_open(SEM_NAME, O_CREAT | O_EXCL, 0666, 1); if (sem == SEM_FAILED) { // 信号量已存在,直接打开 sem = sem_open(SEM_NAME, 0); if (sem == SEM_FAILED) return -1; } // 获取信号量,进入临界区 if (sem_wait(sem) == -1) { sem_close(sem); return -1; } // 一次打开文件并覆盖写入 int f = open(f_name.c_str(), O_CREAT | O_RDWR | O_TRUNC, 07770); if (f < 0) { sem_post(sem); sem_close(sem); return -1; } char c[10]; memset(c, 0, sizeof(c)); sprintf(c, "%d", TestValue); write(f, c, strlen(c)); close(f); // 释放信号量,退出临界区 sem_post(sem); sem_close(sem); return 0; }
读进程的对应同步操作
读进程也需要遵循同样的同步逻辑:
- 打开同一个命名信号量
- 调用
sem_wait()加锁 - 读取文件内容
- 调用
sem_post()解锁 - 关闭信号量
这样就能保证同一时刻只有一个进程(读或写)在访问文件,彻底避免竞态条件导致的读取错误。
最后补充:如果写进程是长期运行的,或者不再需要信号量时,记得调用sem_unlink(SEM_NAME)销毁信号量,避免系统资源残留。
内容的提问来源于stack exchange,提问作者Neanderthal289
相关产品推荐
相关产品推荐

