Qt - 在单独线程中运行功能

时间:2017-06-15 12:18:16

标签: c++ multithreading qt

我有一个按钮点击触发的功能。执行时,它会迭代给定目录中的文件,读取每个文件,然后通过套接字连接将内容发送到客户端。对于发送的每个文件,内容将写回gui。还有一个用于停止迭代的按钮。截至目前,我正在主线程中处理这个问题,但正如预期的那样,gui变得有些反应迟钝。我试图在另一个线程中执行该函数但是,我的实现比在主线程中运行更糟糕!如下所示,一切都在同一个类中。处理此问题的最佳方法是什么?

private:    
QThread mSendDirectoryFilesThread;

private slots:
void onSendDirectoryFilesClicked();
void onStopSendingDirectoryFilesClicked();
void sendDirectoryFiles();

在课程实例化中连接插槽等

moveToThread(&mSendDirectoryFilesThread);
connect(&mSendDirectoryFilesThread, SIGNAL(started()), this, SLOT(sendDirectoryFiles()));

发送按钮点击信号

void MainView::onSendDirectoryFilesClicked()
{
    mSendDirectoryFilesThread.start();
}

发送功能

void MainView::sendDirectoryFiles() {
    QDir packetDir(ui->txtSelectedDirectory->text());
        packetDir.setNameFilters(QStringList() << "*.xml");
    QStringList dirFiles = packetDir.entryList();

    if (dirFiles.count() > 0) {
        ui->btnStopSendingDirectoryFiles->setEnabled(true);

        foreach (QString f, dirFiles) {
            QApplication::processEvents();

            QFile file(ui->txtSelectedDirectory->text() + QDir::separator() + f);
            mDocToSend = getFileXML(file);

            if (mDocToSend.isDocument()) {
                if (mSocket.sendDoc(mDocToSend)) {
                    addToPacketLog(mDocToSend.toString(), "SENT");
                    QThread::sleep(ui->txtTransmitInterval->text().toInt());
                } else {
                    qDebug() << "Nothing to send";
                }
            }
        }
    }
}

停止按钮点击信号

void MainView::onStopSendingDirectoryFilesClicked()
{
    mSendDirectoryFilesThread.exit(0);
}

1 个答案:

答案 0 :(得分:0)

MainView::sendDirectoryFiles未在工作线程中执行,因为connect默认使用Qt::AutoConnection,这意味着在插槽对象的线程中调用该函数,即{{1在你的例子中。您可以通过明确选择this

来更改默认行为
Qt::DirectConnection

进一步考虑

  • 请注意connect(&mSendDirectoryFilesThread, SIGNAL(started()), this, SLOT(sendDirectoryFiles()), Qt::DirectConnection); 应该是线程安全的,但实际情况并非如此。例如,您正在通过调用MainView::sendDirectoryFiles来更改GUI,这是不允许的。

  • 您可能还想在ui->btnStopSendingDirectoryFiles->setEnabled(true);结束时调用mSendDirectoryFilesThread.exit(0),否则您将无法在不首先明确停止操作的情况下执行两次操作。

    < / LI>
  • 如H. Gomaa所指出的那样使用MainView::sendDirectoryFiles可能是一个更清晰的解决方案,但被调用的方法应该仍然是线程安全的。

  • 您可以考虑向派生类QtConcurrent::run添加新信号,该类调用操作而不是启动/停止线程。使用QThreadPoolQThread任务也是一个好主意。