【发布时间】:2021-12-02 16:51:30
【问题描述】:
我正在尝试使用临时序列化文件(数据文件中包含 [no, offset, length] 的指针表和包含数据的数据文件)来实现线程间通信。一个线程应该接收数据(处理它)并将其保存到内存中。第二个线程应该从内存中读取数据并显示结果。 (输入线程只是追加数据,输出线程只是读取。)
我必须将其编译为 32 位,因此我尝试通过读取/写入临时文件来解决 2 GB 的限制。
我已经实现了一个简单的例子。但问题是,如果 I/O 线程同时工作,则输出线程无法正确读取。如果输入线程写入并关闭文件,则输出线程读取并关闭它可以正常工作。我已经与 shared_mutex 和 mutex 进行了同步,但结果相同。
提前感谢您的回复。
更新:根据Update ifstream object after data is written to its file using ofstream 重置标志 (stream.clear()),行为会变得更好,但有时它仍然会失败,有时会通过。
主要:
int main() {
//Start input and output job
std::thread input = std::thread(inputJob);
std::thread output = std::thread(outputJob);
//Wait here for end
input.join();
output.join();
//HERE checking results
return 0;
}
输入作业:
void inputJob() {
is_on = true;
//Loading input data
for (int i = 1; i < 10; i++) {
student s("George", "Patton", 100000 + i, (i % 2) > 0, "0A");
for (int j = 1; j < 4; j++) s.subjects.push_back(subject(rand(), "MA", (j % 5)));
s1.push_back(s);
}
//Save to binary file
std::fstream data_stream, table_stream;
table_stream.open("./table.data", std::fstream::out | std::fstream::trunc | std::fstream::binary);
data_stream.open("./data.data", std::fstream::out | std::fstream::trunc | std::fstream::binary);
size_t off = 0;
if (table_stream.is_open() && data_stream.is_open()) for (size_t i = 0; i < s1.size(); i++) {
std::string tmp = s1[i].toBinaryString();
size_t sz = tmp.size();
table_row t(i, off, sz);
off += sz;
{
std::lock_guard lock(m);
table_stream << t.toBinaryString();
data_stream << tmp;
cout << "Written" << endl;
}
}
table_stream.close();
data_stream.close();
is_on = false;
}
输出作业:
void outputJob() {
//Load from binary file
std::fstream data_stream, table_stream;
table_stream.open("./table.data", std::fstream::in | std::fstream::binary);
data_stream.open("./data.data", std::fstream::in | std::fstream::binary);
if (table_stream.is_open() && data_stream.is_open()) {
size_t row_sz = sizeof(table_row);
std::string line = "";
size_t index = 0;
unsigned table_r = 0;
bool was_empty = false;
while (is_on || (was_empty == false)) {
{
std::lock_guard lock(m);
if (tryGetData(table_stream, line, row_sz, table_r) == 0 && line.empty() == false) {
table_r += row_sz;
was_empty = false;
table_row row;
index = 0;
row.fromBinaryString(line, index, line.size());
if (tryGetData(data_stream, line, row.len, row.off) == 0 && line.empty() == false) {
was_empty = false;
index = 0;
student tmp;
tmp.fromBinaryString(line, index);
if (VAL_CHECK == 1) s2.push_back(tmp);
}
else was_empty = true;
}
else was_empty = true;
}
}
}
table_stream.close();
data_stream.close();
}
尝试获取数据功能:
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()) {
//Set ptr
if (offset != UINT32_MAX) data_stream.seekp(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;
}
【问题讨论】:
-
@SebastianHoffmann 问题是,我需要存储来自输入线程的所有信息,直到输出线程不终止程序。 F. 示例输入线程将学校的所有学生保存到内存中,输出线程读取用户指定的学生并将其显示在 GUI 中。 (与 SQL 类似,但在我的情况下,我不必保存列。我可以节省内存块 - 我试图减小临时文件的大小。)
-
@Ales100 愚蠢的问题:您是否考虑过 SQLite 在多线程模式下编译?
-
写入流并不能保证写入完成时它在磁盘上。如果 'outputJob()' 函数的行为更像 'tail -f
' 那么两个线程可以将一个文件用于 IPC。此外, tryGetData()一次读取一个字符,而不是使用block-read。因此,我希望outputJob()比inputJob()慢。 -
请不要在问题中编辑解决方案公告。接受(即单击旁边的“勾选”)现有答案之一,如果有的话。如果现有答案尚未涵盖您的解决方案,您还可以创建自己的答案,甚至接受它。比较stackoverflow.com/help/self-answer
标签: c++ multithreading fstream