从不同线程的QFile读取 [英] Reading from a QFile in different thread

查看:152
本文介绍了从不同线程的QFile读取的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

读取的最佳方式是什么?QFile 位于与我要读取的线程不同的线程中?

What would be the optimal way of reading from a QFile that resides in a different thread than the one I want to read from?

考虑:

class AFile : public QObject
{
    Q_OBJECT
public:
    AFile(const QString &name, QObject *parent = Q_NULLPTR) : QObject(parent), m_File(name) { m_File.open(QIODevice::ReadWrite); }

public slots:
    void write(const QByteArray &data, qint64 pos) { m_File.seek(pos); m_File.write(data); }

private:
    mutable QFile m_File;
};

class AData : public QObject
{
    Q_OBJECT
public:
    using QObject::QObject;

    void save(const QByteArray &data) { emit saveData(data, 0); }

signals:
    void saveData(const QByteArray &data, qint64 pos) const;
};

AFile file("myfile");
AData data;
QThread *thread = new QThread;

connect(&data, &AData::saveData, &file, &AFile::write);

file.moveToThread(&thread);
thread.start();
data.save("Some data");

//how to concurrently read though?

AFile $ c> QFile ,用于处理对文件的所有写入。它被移动到一个不同的线程,以便不减慢主线程与昂贵的磁盘写操作。多重读取情况由锁或互斥处理,但是会破坏将文件置于不同线程中的目的,因为主程序(希望从中读取)将不得不等待写入完成。在这种情况下,我可以把它留在主线程开始。

AFile is a wrapper around QFile that handles all writes to the file. It is moved to a different thread in order to not slow the main thread with expensive disk write operations. Multi-thraeded read situations are handled by locks or mutex but that would defeat the purpose of having the file in the different thread in the first place since the main one (wanting to read from it) will have to wait for the write to finish so in such a case I may leave it in the main thread to begin with.

我不喜欢的选项是信号和插槽,因为它看起来有点重重量。我将基本上发送一个数据请求,并等待它被读取(通过信号返回数据或发送变量填充数据,并等待一个信号,它已经完成)。

The option I do not quite like are signals and slots because it seems to me a bit heavy weight. I would basically send a request for the data and wait for it to be read (either returning the data via signal or sending variable to be filled with the data and waiting for a signal it has been finished).

经过一些考虑,这似乎是最好的方法,但我不确定这是一个好的设计。

After some consideration this seems to be the best approach but I am not really sure it is a good design.

推荐答案

并行读取是通过拆分请求和指示部分完成的:您首先请求数据,读取器读取数据,然后您对读取数据的指示做出反应。

Concurrent reading is done by splitting the request and indication parts: you first request the data, the reader reads it, then you react to the indication that a data was read.

由于文件对象是从工作线程访问的,我把它封装在 AData 类中。您可以将类移动到工作线程,您从外部调用的信号是线程安全的。

Since the file object is accessed from a worker thread, I've encapsulated it inside the AData class. You can move the class to a worker thread, the signals you call from outside are thread-safe.

也应该可以在 QFile ,但是正确地需要使用Qt的实现细节( core_private 模块)。

It should also be possible to make an asynchronous wrapper around a QFile, but doing it properly would require using Qt's implementation details (core_private module).

// https://github.com/KubaO/stackoverflown/tree/master/questions/async-file-io-39226814
#include <QtWidgets>

class AData : public QObject
{
    Q_OBJECT
    QFile m_file;
public:
    explicit AData(QObject * parent = nullptr) : QObject{parent} {
        connect(this, &AData::save, this, [=](const QByteArray & data, qint64 pos){
            m_file.seek(pos);
            m_file.write(data);
        });
        connect(this, &AData::load, this, [=](qint64 pos, qint64 len){
           m_file.seek(pos);
           if (len == -1) len = m_file.size();
           auto data = m_file.read(len);
           emit loaded(data, pos);
        });
    }
    bool open(const QString & name) {
        m_file.setFileName(name);
        return m_file.open(QIODevice::ReadWrite);
    }
    Q_SIGNAL void save(const QByteArray &data, qint64 pos = 0) const;
    Q_SIGNAL void load(qint64 pos, qint64 len) const;
    Q_SIGNAL void loaded(const QByteArray &data, qint64 pos) const;
};

测试UI演示如何使用它:

A test UI demonstrates how to use it:

int main(int argc, char ** argv) {
    QApplication app{argc, argv};
    struct Thread : QThread {
        ~Thread() { quit(); wait(); }
    } ioThread;
    AData data;
    data.open("myfile");
    data.moveToThread(&ioThread);
    ioThread.start();

    QWidget ui;
    QGridLayout layout{&ui};
    QTextEdit text;
    QPushButton load{"Load"};
    QPushButton save{"Save"};
    QPushButton clear{"Clear"};
    layout.addWidget(&text, 0, 0, 1, 2);
    layout.addWidget(&load, 1, 0);
    layout.addWidget(&save, 1, 1);
    layout.addWidget(&clear, 2, 0, 1, 2);
    ui.show();

    using Q = QObject;
    Q::connect(&load, &QPushButton::clicked, &data, [&]{
        data.load(0, -1);
    });
    Q::connect(&data, &AData::loaded, &app, [&](const QByteArray & data, qint64){
       text.setPlainText(QString::fromUtf8(data));
    });
    Q::connect(&save, &QPushButton::clicked, &data, [&]{
        data.save(text.document()->toPlainText().toUtf8());
    });
    Q::connect(&clear, &QPushButton::clicked, &text, &QTextEdit::clear);

    return app.exec();
}
#include "main.moc"

这篇关于从不同线程的QFile读取的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆