Qt线程池执行事件循环

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_H

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_H

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;
}

Qt线程池执行事件循环
http://yoursite.com/2019/04/18/Qt线程池执行事件循环/
作者
还在输入
发布于
2019年4月18日
许可协议