32位程序用临时文件实现线程通信时并发读写异常问题求助
问题根因
- 写端文件流未强制刷入磁盘:C++标准库的fstream默认开启用户态缓冲区,加锁写入后数据仅存在进程缓冲区,未同步到内核文件系统,读线程无法感知到新写入的内容。
- 读指针操作函数误用:
tryGetData中读取数据前调用seekp设置写指针,读场景下必须使用seekg设置读指针,这是偶发读取失败的核心原因之一。 - 流状态重置不完整:读线程触发eof后仅调用
clear()清除标志位不够,需要同步当前文件的实际长度,避免读到无效的尾端数据。 - 全局标志
is_on无同步保护:普通全局变量在多线程场景下会被编译器优化为寄存器缓存,输出线程可能无法及时感知到输入线程修改的is_on状态,导致逻辑提前终止或死循环。 - 写入顺序逻辑风险:当前先写指针表再写数据文件,极端情况下指针表写入完成后数据还未落盘,读线程拿到指针表读取数据时会读到不完整内容。
修复方案
- 输入线程写入后强制刷入缓冲区
在输入线程的锁块内,写完两个流后追加flush调用:
{ std::lock_guard lock(m); table_stream << t.toBinaryString(); data_stream << tmp; // 新增刷入逻辑 table_stream.flush(); data_stream.flush(); cout << "Written" << endl; }
- 修复
tryGetData的指针设置函数
把seekp改为seekg,同时在读取前先清除流状态:
int tryGetData(std::fstream &data_stream, std::string& data, size_t data_sz, size_t offset) { int ret = 0; data = ""; if (data_stream.is_open()) { // 新增清除流状态 data_stream.clear(); // 把seekp改为seekg if (offset != UINT32_MAX) data_stream.seekg(offset); char c; while (data_sz > 0 && data_stream.get(c)) { data.push_back(c); data_sz--; } if (data_stream.eof()) ret = 1; } return ret; }
替换
is_on为原子变量
将全局的is_on改为std::atomic<bool>,避免多线程可见性问题,无需额外加锁即可保证读写的原子性和可见性。调整写入顺序
先写数据文件,再写指针表,保证读线程拿到指针表的时候对应数据已经落盘:
{ std::lock_guard lock(m); // 先写数据,再写索引 data_stream << tmp; table_stream << t.toBinaryString(); data_stream.flush(); table_stream.flush(); cout << "Written" << endl; }
如果需要更高性能,可以调整缓冲区大小,或者使用操作系统级的内存映射文件代替直接fstream读写,性能会比逐字符get高很多。
内容的提问来源于stack exchange,提问作者Ales100
相关产品推荐
相关产品推荐

