总结
两个线程可以同时打开一个文件,并且同时写和读都是可以的,都没有限制
但是Qthread读写没有任何数据完整性保证的锁,也就是说,数据乱了不归QThread、QFile、QStream管
结论一:线程1写入abc,线程2同时写入123,可能出现a1b2c3
结论二:读取也一样,线程1正在写入abcdef刚写了abc,线程2读取,就只能读到abc
写了一个程序一个写入a-z一个写入0-9
证明结论一:
证明结论二:
打开文件有概率读到的最后一个字符不一定是z或者9
1. 一个线程在读的时候另一个线程同时读:
这种情况通常是可行的,因为多个线程可以同时读取文件而不会引发问题。读取操作不会改变文件的内容,因此多个线程可以安全地并发读取文件。主要问题在于性能,如果多个线程同时读取大文件,可能会导致竞争条件,降低性能。
2. 一个线程在写的时候另一个线程同时读:
这种情况可能导致一些问题,如下所示:
- 数据不一致性:当一个线程正在写入文件时,另一个线程可能读取到部分旧数据和部分新数据,导致数据不一致。这是因为写入线程正在修改文件,而读取线程同时尝试读取文件内容。
- 文件损坏:同时进行读取和写入操作可能导致文件损坏。如果一个线程尝试写入文件的某一部分,而另一个线程同时尝试读取相同的部分,文件可能会变得不完整或损坏。
为了避免这些问题,通常需要使用互斥锁或其他同步机制来确保在任何给定时间只有一个线程可以访问文件。
3. 一个线程在写的时候另一个线程同时写:
这种情况通常是危险的,因为同时进行写入操作可能导致以下问题:
- 数据不一致性:如果两个线程同时写入文件,它们可能会相互干扰,导致文件内容混乱或不一致。例如,一个线程可能正在修改文件的一部分,而另一个线程也试图修改相同的部分。
- 文件损坏:同时进行写入操作可能导致文件损坏,因为两个线程可能会在相同的位置写入数据,这可能导致数据丢失或文件内容被破坏。
结论:线程无论如何都可以读取文件内容,但是如果另一个线程在写入,那么读出的数据对不保证了
测试代码:
#include <QCoreApplication>
#include <QThread>
#include <QFile>
#include <QTextStream>
#include <QDebug>
// 共享的标志,用于控制线程停止
bool stopWriting = false;
bool stopReading = false;
// 1号线程:不停地写入文件
class WriteThread : public QThread
{
public:
WriteThread(const QString& fileName) : fileName_(fileName) {}
protected:
void run() override
{
QFile file(fileName_);
if (file.open(QIODevice::WriteOnly | QIODevice::Text))
{
QTextStream stream(&file);
int counter = 0;
QString baseString = "9999999999999999999999999999999999999999999999999999";
QString resultString;
for (int i = 0; i < 1; i++) {
resultString += baseString;
}
while (!stopWriting)
{
读
//QString read = stream.readLine();
//qDebug() << "[thread 1] Reading: " << read;
// 写
QString content = QString::number(counter++);
stream << content << "\n";
//qDebug() << "[thread 1] Write: " << content;
stream.flush();
QThread::msleep(200); // 等待1秒
}
file.close();
}
else
{
qDebug() << "Unable to open file for writing.";
}
}
private:
QString fileName_;
};
// 2号线程:不停地读取文件并输出内容
class ReadThread : public QThread
{
public:
ReadThread(const QString& fileName) : fileName_(fileName) {}
protected:
void run() override
{
QFile file(fileName_);
if (file.open(QIODevice::ReadOnly | QIODevice::Text))
{
QTextStream stream(&file);
int counter = 0;
while (!stopReading)
{
// 读
// 使用 QList 存储最后两行
QList<QString> lastTwoLines;
while (!stream.atEnd()) {
QString line = stream.readLine();
lastTwoLines.append(line);
if (lastTwoLines.size() > 3) {
lastTwoLines.removeFirst(); // 移除列表中的第一行,保持只有最后两行
}
}
qDebug() << "[thread 2] ReadOnly: " << lastTwoLines;
写
//QString content = "[thread 2] Write #" + QString::number(counter++);
//stream << content << "\n";
//qDebug() << "[thread 2] Write: " << content;
//stream.flush();
QThread::msleep(100); // 等待1秒
}
file.close();
}
else
{
qDebug() << "Unable to open file for reading.";
}
}
private:
QString fileName_;
};
int main(int argc, char* argv[])
{
QCoreApplication a(argc, argv);
QString fileName = "example.txt";
// 创建并启动1号线程:不停地写入文件
WriteThread writeThread(fileName);
writeThread.start();
// 创建并启动2号线程:不停地读取文件
ReadThread readThread(fileName);
readThread.start();
//qDebug() << "Press Enter to stop...";
//getchar(); // 等待用户按下Enter键
设置停止标志以停止线程
//stopWriting = true;
//stopReading = true;
// 等待线程完成执行
writeThread.wait();
readThread.wait();
return a.exec();
}
flush函数是干嘛的?
flush 函数用于将缓冲区中的数据立即写入文件或输出流,而不必等待缓冲区满或程序退出。它的作用是强制将缓冲区中的数据刷新到文件或输出设备,以确保数据被实际写入,而不仅仅是暂时保存在内存中。
在文件操作中,flush 通常与文件写入操作一起使用,以确保数据被及时写入文件。如果不使用 flush,数据可能会在内存中积累一段时间,直到缓冲区满或程序结束才会被写入文件。但是,使用 flush 可以立即将数据写入文件,而不必等待缓冲区填满。
在输出流中,例如 QTextStream,flush 可以用于立即将文本输出到目标设备,而不必等待缓冲区满。这对于实时数据输出和调试信息的显示非常有用,因为它可以确保数据立即可见,而不必等待输出缓冲区填满。
总之,flush 用于强制将缓冲区中的数据刷新到目标,以确保数据被及时写入或显示。在需要立即将数据写入文件或输出设备时,通常会使用 flush 函数。
一边flush一边读取会发生什么?
如果系统正在执行flush一个字符串进去比如123456789我此时read,还没完全flush完成我会读到其中一部分么?
是的,如果系统正在执行 flush 操作将字符串 "123456789" 写入文件,而此时另一个线程尝试读取文件内容,有可能会读取到部分数据,比如 "123"。这是因为在写入过程中,文件的部分内容已经被写入到文件,但可能还没有完全写入完成。
在多线程环境中,这种情况可能会导致读取线程读取到文件的不完整部分。因此,如果您希望在多线程环境中进行文件访问,您可能需要使用同步机制,如互斥锁,来确保在进行写入操作时不允许同时进行读取操作。这可以避免读取到不完整或不正确的数据。
多个线程操作同一个实例结论
允许将主线程的QFile file()传入其他线程。
但是当其中一个线程持操作这个file的时候,另一个线程也打算同时操作这个file它就会报错,报错的内容都是随机的。因为第二个线程不一定什么时候突然也开始用这个file实例。可以看到的是虽然报错了,但是提前拿到file使用权的那个线程完全不会崩一直在进行写入操作。
说白了就是一个多个线程同时请求访问同一个函数或资源时产生的随机异常。
但是只要给两个线程都上一个互斥锁,就不会崩。完美运行
加上互斥锁,从main传入QFile,两个线程同时写入的程序
#include <QCoreApplication>
#include <QThread>
#include <QFile>
#include <QTextStream>
#include <QDebug>
#include <QMutex>
QMutex fileMutex;
bool stopWriting = false;
bool stopReading = false;
class WriteThread : public QThread
{
public:
WriteThread(QFile* f) : file(f) {}
protected:
void run() override
{
if (file->open(QIODevice::WriteOnly | QIODevice::Text))
{
QTextStream stream(file);
int counter = 0;
while (!stopWriting)
{
QString content = "[Thread 1] Write #" + QString::number(counter++);
//QMutexLocker locker(&fileMutex);
stream << content << "\n";
qDebug() << "[Thread 1] Write: " << content;
stream.flush();
QThread::msleep(10); // 等待1毫秒
}
file->close();
}
else
{
qDebug() << "Unable to open file for writing.";
}
}
private:
QFile* file;
};
class ReadThread : public QThread
{
public:
ReadThread(QFile* f) : file(f) {}
protected:
void run() override
{
if (file->open(QIODevice::WriteOnly | QIODevice::Text))
{
QTextStream stream(file);
int counter = 0;
while (!stopReading)
{
QString content = "[Thread 2] Write #" + QString::number(counter++);
//QMutexLocker locker(&fileMutex);
stream << content << "\n";
qDebug() << "[Thread 2] Write: " << content;
stream.flush();
QThread::msleep(10); // 等待1毫秒
}
file->close();
}
else
{
qDebug() << "Unable to open file for reading.";
}
}
private:
QFile* file;
};
int main(int argc, char* argv[])
{
QCoreApplication a(argc, argv);
QString fileName = "example.txt";
QFile file(fileName);
WriteThread writeThread(&file);
writeThread.start();
ReadThread readThread(&file);
readThread.start();
return a.exec();
}