Qt的线程池有一个专门的类QThreadPool,内置全局单例,它可以设置最大线程数,假设线程池添加了10个任务,设置最大线程数为3,那么这10个任务就会排队等待3个线程处理。QRunnable是线程池运行的基本工作类,它是一个虚基类,需要用户继承然后重写run(),线程实际运行的就是run()函数里面的代码。这个类不继承QObject,所以直接继承无法使用信号槽。于是采用多继承,先继承QObject,然后继承QRunnable。这个基类没有实现exec(),也就是说run()函数结束后,这个对象也会销毁。如果需要事件循环,那么可以使用QEventloop,达到同样的效果,只要注意及时退出事件循环。这个QRunnable默认是自动销毁,就是说run()执行完了自动销毁,不要要用户自己释放。也可以通过task->setAutoDelete(false)设置不自动销毁。下面给一个代码示例。
downloadfiletask.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| #ifndef DOWNLOADFILETASK_H #define DOWNLOADFILETASK_H
#include <QObject> #include <QRunnable> #include <QEventLoop> #include "fileprocess.h" class DownloadFileTask : public QObject,public QRunnable { Q_OBJECT public: explicit DownloadFileTask(MmsRemoteIedRuner *mr,RFileProcess::DownloadMode mode,QString remotepath,QObject *parent = nullptr); virtual ~DownloadFileTask();
void setDownloadFileList(QStringList& list); signals:
public slots: void filesDownloadedFinished();
protected: void run();
private:
RFileProcess::DownloadMode m_downloadFileMode; QString m_remotePath; QStringList m_downloadFileList;
QEventLoop loop; RFileProcess *m_pfilePro; };
#endif
|
downloadfiletask.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| #include "downloadfiletask.h" #include "mmsoption.h" #include <QDebug>
DownloadFileTask::DownloadFileTask(MmsRemoteIedRuner *mr, RFileProcess::DownloadMode mode, QString remotepath, QObject *parent) : m_downloadFileMode(mode), m_remotePath(remotepath), QObject(parent) {
m_pfilePro=new RFileProcess(mr,m_downloadFileMode,m_remotePath);
connect(m_pfilePro,SIGNAL(filesDownloadFinished()),this,SLOT(filesDownloadedFinished())); } DownloadFileTask::~DownloadFileTask() {
}
void DownloadFileTask::run() { if(m_downloadFileMode==RFileProcess::DownloadWantedModel){ m_pfilePro->setDownloadFileList(m_downloadFileList); } m_pfilePro->listDirectory(); loop.exec();
} void DownloadFileTask::setDownloadFileList(QStringList& list) { m_downloadFileList=list; }
void DownloadFileTask::filesDownloadedFinished() {
if(m_pfilePro){ m_pfilePro->deleteLater(); } loop.quit();
}
|
使用示例
1 2 3 4 5 6 7 8 9 10
| QThreadPool m_pThreadPool=QThreadPool::globalInstance();
m_pThreadPool->setMaxThreadCount(3); for(int i=0;i<p_iedManager->count();i++){
DownloadFileTask *task=new DownloadFileTask();
m_pThreadPool->start(task);
}
|
BUG修复
上述代码在实际运行的时候,会提示一个警告信息:
QEventDispatcherUNIX: internal error, wakeUps.testAndSetRelease(1, 0) failed!
会导致程序崩溃。通过使用gdb调试查看堆栈信息,发现程序断在 run()函数里面的loop.exec()这里。于是我猜想QEventLoop 被定义为成员变量,所以它和创建它的类属于同一个线程,而在run()里面则是另外一个线程。于是修改上述代码如下:
downloadfiletask.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| #ifndef DOWNLOADFILETASK_H #define DOWNLOADFILETASK_H
#include <QObject> #include <QRunnable> #include <QEventLoop> #include "fileprocess.h" class DownloadFileTask : public QObject,public QRunnable { Q_OBJECT public: explicit DownloadFileTask(MmsRemoteIedRuner *mr,RFileProcess::DownloadMode mode,QString remotepath,QObject *parent = nullptr); virtual ~DownloadFileTask();
void setDownloadFileList(QStringList& list); signals:
public slots:
protected: void run();
private:
RFileProcess::DownloadMode m_downloadFileMode; QString m_remotePath; QStringList m_downloadFileList; RFileProcess *m_pfilePro; };
#endif
|
downloadfiletask.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| #include "downloadfiletask.h" #include "mmsoption.h" #include <QDebug>
DownloadFileTask::DownloadFileTask(MmsRemoteIedRuner *mr, RFileProcess::DownloadMode mode, QString remotepath, QObject *parent) : QObject(parent), m_downloadFileMode(mode), m_remotePath(remotepath)
{
m_pfilePro=new RFileProcess(mr,m_downloadFileMode,m_remotePath);
} DownloadFileTask::~DownloadFileTask() { if(m_pfilePro){ m_pfilePro->deleteLater(); } }
void DownloadFileTask::run() { if(m_downloadFileMode==RFileProcess::DownloadWantedModel){ m_pfilePro->setDownloadFileList(m_downloadFileList); } QEventLoop loop; connect(m_pfilePro,SIGNAL(filesDownloadFinished()),&loop,SLOT(quit())); m_pfilePro->listDirectory(); loop.exec();
} void DownloadFileTask::setDownloadFileList(QStringList& list) { m_downloadFileList=list; }
|