Qt - 在单独的线程中运行函数

Qt - Run function in Separate Thread

本文关键字:运行 函数 线程 单独 Qt      更新时间:2023-10-16

我有一个由按钮单击触发的函数。执行时,它会迭代给定目录中的文件,读取每个文件,然后通过套接字连接将内容发送到客户端。对于发送的每个文件,内容将写回 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);
}
MainView::sendDirectoryFiles

不会在工作线程中执行,因为connect默认使用Qt::AutoConnection,这意味着该函数在 slot 对象的线程中调用,即this在您的示例中。您可以通过显式选择Qt::DirectConnection来更改默认行为:

connect(&mSendDirectoryFilesThread, SIGNAL(started()), this, SLOT(sendDirectoryFiles()), Qt::DirectConnection);

进一步考虑

  • 请注意,MainView::sendDirectoryFiles应该是线程安全的,但事实并非如此。例如,您正在通过调用ui->btnStopSendingDirectoryFiles->setEnabled(true);来更改 GUI,这是不允许的。

  • 您可能还希望在MainView::sendDirectoryFiles结束时调用mSendDirectoryFilesThread.exit(0),否则如果不先显式停止操作,您将无法执行两次操作。

  • 如 H. Gomaa 指出的那样,使用QtConcurrent::run可能是一个更清晰的解决方案,但调用的方法仍然应该是线程安全的。

  • 您可以考虑将新信号添加到派生类QThread中,该类调用操作而不是启动/停止线程。使用QThreadPoolQRunnable任务也可能是一个好主意。