本文主要是介绍Qt中实现多线程导出数据功能的四种方式小结,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
《Qt中实现多线程导出数据功能的四种方式小结》在以往的项目开发中,在很多地方用到了多线程,本文将记录下在Qt开发中用到的多线程技术实现方法,以导出指定范围的数字到txt文件为例,展示多线程不同的实现方...
前言
在以往的项目开发中,在很多地方用到了多线程。针对不同的业务逻辑,需要使用不同的多线程实现方法,来达到优化项目的目的。本文记录下在Qt开发中用到的多线程技术实现方法,以导出指定范围的数字到txt文件为例,展示多线程不同的实现方式。
示例已上传到gittee,地址:https://gitee.com/zbylalalala1/qt_-thread-demo.git
导出文件的示例工具类
首先提供一个工具类,用于将指定范围的数字写入txt文件。
#ifndef UTILITIES_H #define UTILITIES_H #include <QString> #include <QFile> #include <QTextStream> #include <QDateTime> #include <QDir> #include <QDebug> class Utilities { public: static bool writeNumbersToFile(int start, int end, const QString& prefix = "numbers") { if (start > end) { qDebug() << "起始数字不能大于结束数字"; return false; } // 获取当前时间并格式化为文件名 QDateTime currentTime = QDateTime::currentDateTime(); QString timeString = currentTime.toString("yyyy-MM-dd_hh-mm-ss"); QString fileName = QString("%1_%2_to_%3_%4.txt") .arg(prefix) .arg(start) .arg(end) .arg(timeString); // 创建文件对象 QFile file(fileName); // 以写入模式打开文件 if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { qDebug() << "无法创建文件:" << fileName; return false; } // 创建文本流 QTextStream out(&file); // 写入指定范围的数字 int count = 0; for (int i = start; i <= end; ++i) { out << i; count++; // 每10个数字换行 if (count % 10 == 0 || i == end) { out << "\n"; } else { out << " "; // 数字之间用空格分隔 } } // 关闭文件 file.close(); qDebug() << "成功写入文件:" << fileName; qDebug() << "文件路径:" << QDir::currentPath() + "/" + fileName; qDebug() << "写入数字范围:" << start << "到" << end << ",共" << (end - start + 1) << "个数字"; return true; } // 获取当前工作目录 static QString getCurrentPath() { return QDir::currentPath(); } // 检查文件是否存在 static bool fileExists(const QString& fileName) { QFile file(fileName); return file.exists(); } }; #endif // UTILITIES_H
QThread
使用QThread类来创建线程,是Qt中最简单的一种多线程实现方式,不过一般不建议使用,因为它的功能比较有限。
使用QThread的方式为:继承QThread并重写run()函数。
ExportThread.h
#ifndef EXPORTTHREAD_H #define EXPORTTHREAD_H #include <QThread> #include <QDebug> #include "Utilities.h" class ExportThread : public QThread { Q_OBJECT public: explicit ExportThread(QObject *parent = nullptr); // 设置导出参数 void setExportParams(int start = 1, int end = 10000, const QString& prefix = "numbers"); protected: void run() override; signals: void exportStarted(); void exportFinished(bool success, const QString& message); void progressUpdate(int current, int total); private: int m_start; int m_end; QString m_prefix; }; #endif // EXPORTTHREAD_H
ExportThread.cpp
#include "ExportThread.h"
#include <QDateTime>
#include <QDir>
ExportThread::ExportThread(QObject *parent)
: QThread(parent)
, m_start(1)
, m_end(10000)
, m_prefix("numbers")
{
}
void ExportThread::setExportParams(int start, int end, const QString& prefix)
{
m_start = start;
m_end = end;
m_prefix = prefix;
}
void ExportThread::run()
{
qDebug() << "导出线程开始运行...";
emit exportStarted();
try {
bool success = Utilities::writeNumbersToFile(m_start, m_end, m_prefix);
if (success) {
emit exportFinished(true, QString("文件导javascript出成功!范围:%1-%2").arg(m_start).arg(m_end));
http://www.chinasem.cn } else {
emit exportFinished(false, "文件导出失败!");
}
qDebug() << "导出线程完成";
} catch (const std::exception& e) {
qDebug() << "导出过程中发生异常:" << e.what();
emit exportFinished(false, QString("导出过程中发生异常: %1").arg(e.what()));
}
}
使用方式:
ExportThread *exportThread = new ExportThread(this); exportThread->setExportParams(1, 10000, "numbers"); exportThread->start();
QObject的moveToThread方法实现多线程
QObject的moveToThread方法可以将一个QObject对象移动到指定的线程中,实现多线程。
使用方式:
QObject *obj = new QObject(); QThread *thread = new QThread(); obj->moveToThread(thread); thread->start();
示例:
FileExportWorker.h
#ifndef FILEEXPORTWORKER_H #define FILEEXPORTWORKER_H #include <QObject> #include "Utilities.h" class FileExportWorker : public QObject { Q_OBJECT public: explicit FileExportWorker(QObject *parent = nullptr); void exportNumbers(int start, int end, const QString& prefix); signals: void progressUpdated(int current, int total); void statusUpdated(const QString& status); public slots: }; #endif // FILEEXPORTWORKER_H
FileExportWorker.cpp
#include "FileExportWorker.h" #include <QFile> #include <QTextStream> #include <QDateTime> #include <QDir> #include <QDebug> #include <QThread> #include <QCoreApplication> FileExportWorker::FileExportWorker(QObject *parent) : QObject(parent) , m_start(1) , m_end(10000) , m_prefix("numbers") , m_shouldStop(false) { } void FileExportWorker::setExportParams(int start, int end, const QString& prefix) { m_start = start; m_end = end; m_prefix = prefix; } void FileExportWorker::doExport() { qDebug() << "Worker线程ID:" << QThread::currentThreadId(); qDebug() << "开始导出任务..."; m_shouldStop = false; emit exportStarted(); emit statusUpdated("正在准备导出..."); try { bool success = false; emit statusUpdated("使用自定义参数导出..."); success = exportNumbersWithProgress(); if (m_shouldStop) { emit exportFinished(false, "导出已被用户取消"); } else if (success) { emit exportFinished(true, QString("文件导出成功!范围:%1-%2").arg(m_start).arg(m_end)); } else { emit exportFinished(false, "文件导出失败!"); } } catch (const std::exception& e) { qDebug() << "导出过程中发生异常:" << e.what(); emit exportFinished(false, QString("导出过程中发生异常: %1").arg(e.what())); } qDebug() << "导出任务完成"; } void FileExportWorker::stopExport() { m_shouldStop = true; emit statusUpdated("正在停止导出..."); } bool FileExportWorker::exportNumbersWithProgresspython() { // 获取当前时间并格式化为文件名 QDateTime currentTime = QDateTime::currentDateTime(); QString timeString = currentTime.toString("yyyy-MM-dd_hh-mm-ss"); QString fileName = QString("%1_%2_to_%3_%4.txt") .arg(m_prefix) .arg(m_start) .arg(m_end) .arg(timeString); // 创建文件对象 QFile file(fileName); // 以写入模式打开文件 if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { qDebug() << "无法创建文件:" << fileName; return false; } // 创建文本流 QTextStream out(&file); int total = m_end - m_start + 1; int count = 0; // 写入指定范围的数字 for (int i = m_start; i <= m_end; ++i) { if (m_shouldStop) { file.close(); QFile::remove(fileName); // 删除未完成的文件 return false; } out << i; count++; js // 每10个数字换行 if (count % 10 == 0 || i == m_end) { out << "\n"; } else { out << " "; // 数字之间用空格分隔 } // 每处理100个数字发送一次进度更新 if (count % 100 == 0 || i == m_end) { emit progressUpdated(count, total); emit statusUpdated(QString("已处理 %1/%2 个数字").arg(count).arg(total)); // 让出CPU时间,允许其他操作 QCoreApplication::processEvents(); } } // 关闭文件 file.close(); qDebug() << "成功写入文件:" << fileName; qDebug() << "文件路径:" << QDir::currentPath() + "/" + fileName; qDebug() << "写入数字范围:" << m_start << "到" << m_end << ",共" << total << "个数字"; return true; }
QConcurrent实现多线程导出数据
QConcurrent是Qt提供的一个并发编程框架,用于简化多线程编程。它提供了一些方便的函数和类,用于在多个线程中执行任务。本示例通过QConcurrent实现导出任务,实现多线程导出数据。
使用方式:
QFuture<bool> future = QConcurrent::run(this, &FileExportWorker::exportNumbersWithProgress);
示例:
FileExportWorker.h
#ifndef CONCURRENTEXPORTER_H #define CONCURRENTEXPORTER_H #include <QObject> #include <QString> #include <QFuture> #include <QFutureWatcher> #include <QtConcurrent> #include "Utilities.h" class ConcurrentExporter : public QObject { Q_OBJECT public: explicit ConcurrentExporter(QObject *parent = nullptr); // 开始导出任务 void startExport(int start = 1, int end = 10000, const QString& prefix = "concurrent"); // 取消导出任务 void cancelExport(); // 检查是否正在运行 bool isRunning() const; signals: void exportStarted(); void exportFinished(bool success, const QString& message); private slots: void onExportFinished(); private: QFutureWatcher<bool> *m_watcher; QFuture<bool> m_future; int m_start; int m_end; QString m_prefix; }; #endif // CONCURRENTEXPORTER_H
FileExportWorker.cpp
#include "ConcurrentExporter.h" #include <QFile> #include <QTextStream> #include <QDateTime> #include <QDir> #include <QDebug> #include <QThread> #include <QCoreApplication> #include <QtConcurrent/QtConcurrentRun> ConcurrentExporter::ConcurrentExporter(QObject *parent) : QObject(parent) , m_watcher(new QFutureWatcher<bool>(this)) , m_start(1) , m_end(10000) , m_prefix("concurrent") { // 连接QFutureWatcher的信号 connect(m_watcher, &QFutureWatcher<bool>::finished, this, &ConcurrentExporter::onExportFinished); } void ConcurrentExporter::startExport(int start, int end, const QString& prefix) { if (isRunning()) { qDebug() << "导出任务已在运行中"; return; } m_start = start; m_end = end; m_prefix = prefix; qDebug() << "使用Qt Concurrent开始导出任务..."; qDebug() << "当前线程ID:" << QThread::currentThreadId(); emit exportStarted(); m_future = QtConcurrent::run([=]() { qDebug() << "工作线程ID:" << QThread::currentThreadId(); return Utilities::writeNumbersToFile(start, end, prefix); }); // 设置QFutureWatcher监视QFuture m_watcher->setFuture(m_future); } void ConcurrentExporter::cancelExport() { if (isRunning()) { m_future.cancel(); } } bool ConcurrentExporter::isRunning() const { return m_future.isRunning(); } void ConcurrentExporter::onExportFinished() { bool success = false; QString message; if (m_future.isCanceled()) { message = "导出任务已被取消"; } else { try { success = m_future.result(); if (success) { message = QString("文件导出成功!范围:%1-%2").arg(m_start).arg(m_end); } else { message = "文件导出失败!"; } } catch (const std::exception& e) { message = QString("导出过程中发生异常: %1").arg(e.what()); } } emit exportFinished(success, message); qDebug() << "Qt Concurrent导出任务完成:" << message; }
QRunnable结合QThreadPool方法实现多线程导出数据
QRunnable是Qt提供的一个接口,用于在多线程中执行任务。QThreadPool是一个线程池,用于管理多个线程。本示例通过QRunnable接口实现导出任务,通过QThreadPool线程池管理线程,实现多线程导出数据。
使用方式:
QThreadPool *pool = QThreadPool::globalInstance(); RunnableExportTask *task = new RunnableExportTask(1, 10000, "numbers"); pool->start(task);
示例:
RunnableExportTask.h
#ifndef RUNNABLEEXPORTTASK_H #define RUNNABLEEXPORTTASK_H #include <QRunnable> #include <QObject> #include <QString> #include <QDebug> #include "Utilities.h" // 由于QRunnable不继承QObject,我们需要一个信号发射器 class ExportTaskNotifier : public QObject { Q_OBJECT public: explicit ExportTaskNotifier(QObject *parent = nullptr) : QObject(parent) {} void emitStarted() { emit exportStarted(); } void emitFinished(bool success, const QString& message) { emit exportFinished(success, message); } void emitProgress(const QString& status) { emit progressUpdated(status); } signals: void exportStarted(); void exportphpFinished(bool success, const QString& message); void progressUpdated(const QString& status); }; class RunnableExportTask : public QRunnable { public: explicit RunnableExportTask(int start = 1, int end = 10000, const QString& prefix = "runnable"); // 设置通知器,用于发送信号 void setNotifier(ExportTaskNotifier *notifier); // 设置导出参数 void setExportParams(int start, int end, const QString& prefix); // QRunnable接口实现 void run() override; private: int m_start; int m_end; QString m_prefix; ExportTaskNotifier *m_notifier; }; #endif // RUNNABLEEXPORTTASK_H
RunnableExportTask.cpp
#include "RunnableExportTask.h" #include <QThread> #include <QDebug> RunnableExportTask::RunnableExportTask(int start, int end, const QString& prefix) : m_start(start) , m_end(end) , m_prefix(prefix) , m_notifier(nullptr) { // 设置任务完成后自动删除 setAutoDelete(true); } void RunnableExportTask::setNotifier(ExportTaskNotifier *notifier) { m_notifier = notifier; } void RunnableExportTask::setExportParams(int start, int end, const QString& prefix) { m_start = start; m_end = end; m_prefix = prefix; } void RunnableExportTask::run() { qDebug() << "QRunnable任务开始运行..."; qDebug() << "当前线程ID:" << QThread::currentThreadId(); if (m_notifier) { m_notifier->emitStarted(); m_notifier->emitProgress("QRunnable任务:正在准备导出..."); } try { if (m_notifier) { m_notifier->emitProgress("QRunnable任务:开始写入文件..."); } bool success = Utilities::writeNumbersToFile(m_start, m_end, m_prefix); if (success) { QString message = QString("文件导出成功!范围:%1-%2").arg(m_start).arg(m_end); if (m_notifier) { m_notifier->emitProgress("QRunnable任务:导出完成"); m_notifier->emitFinished(true, message); } qDebug() << "QRunnable任务完成:" << message; } else { QString message = "文件导出失败!"; if (m_notifier) { m_notifier->emitFinished(false, message); } qDebug() << "QRunnable任务失败:" << message; } } catch (const std::exception& e) { QString message = QString("导出过程中发生异常: %1").arg(e.what()); qDebug() << "QRunnable任务异常:" << message; if (m_notifier) { m_notifier->emitFinished(false, message); } } qDebug() << "QRunnable任务结束"; }
到此这篇关于Qt中实现多线程导出数据功能的四种方式小结的文章就介绍到这了,更多相关Qt多线程导出数据内容请搜索China编程(www.chinasem.cn)以前的文章或继续浏览下面的相关文章希望大家以后多多支持China编程(www.chinasem.cn)!
这篇关于Qt中实现多线程导出数据功能的四种方式小结的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!