Qt中可以有多种使用线程的方式:
待补充
任务类代码如下:
class PrintTask : public QObject
{
Q_OBJECT
public:
PrintTask();
~PrintTask();
signals:
void mySignal();
public slots:
void RunTask();
void Test();
void StopTask();
public:
volatile bool m_stop;
};
volatile 关键字:当多个线程都要用到某一个变量且该变量的值会被改变时应该用volatile声明,该关键字的作用是防止编译器优化把变量从内存装入CPU寄存器中;
isInterruptionRequested 和 requestInterruption配套使用。requestInterruption请求中断线程,但不会停止事件循环,isInterruptionRequested本质是加锁判断,所以不要频繁调用;
PrintTask::PrintTask()
{
m_stop = false;
}
PrintTask::~PrintTask()
{
}
void PrintTask::RunTask()
{
qDebug() << "RunTask 被调用线程ID为:" << QThread::currentThread();
while(!QThread::currentThread()->isInterruptionRequested()) // 或者用!m_stop
{
Test();
//QCoreApplication::processEvents();
QThread::sleep(1);
}
qDebug() << "RunTask 退出:" << QThread::currentThread();
}
void PrintTask::StopTask()
{
qDebug() << "StopTask()" << QThread::currentThread();
m_stop = true;
}
void PrintTask::Test()
{
qDebug() << "Test 被调用线程ID为:" << QThread::currentThread();
emit mySignal();
}
主函数初始化,可以连接deleteLater让线程退出时自杀,尽量避免手动调用delete去删除对象。也可以在线程finished后手动处理。
m_Thread = new QThread(this);
m_printTask = new PrintTask();
m_printTask->moveToThread(m_Thread);
// 线程启动后调用RunTask
//connect(m_Thread, &QThread::started, m_printTask, &PrintTask::RunTask);
// 线程退出后删除任务对象
//connect(m_Thread, &QThread::finished, m_printTask, &PrintTask::deleteLater);
// 线程完成
connect(m_Thread, &QThread::finished, this, &Widget::ThreadFinished);
connect(this, &Widget::StartThread, m_printTask, &PrintTask::RunTask, Qt::QueuedConnection);
启动线程:
m_Thread->start();
// 调用任务的函数。要使用信号槽,不能直接调用任务的函数,直接调用是在主线程中运行;
emit StartThread();
停止线程:
m_Thread->requestInterruption(); // 或者调用任务的StopTask(),直接调用StopTask是在主线程中运行;
m_Thread->quit();
m_Thread->wait();
使用QMetaObject::invokeMethod异步执行,可以在worker所在线程执行方法;
class Worker : public QObject
{
Q_OBJECT
public slots:
void doWork()
{
// 执行耗时操作
while (!m_stopFlag) {
// do something
}
}
void stopWork()
{
m_stopFlag = true;
}
private:
bool m_stopFlag = false;
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Worker worker;
QThread thread;
worker.moveToThread(&thread);
thread.start();
// 请求线程停止并等待线程退出
QMetaObject::invokeMethod(&worker, "stopWork", Qt::QueuedConnection);
thread.quit();
thread.wait();
return a.exec();
}
QRunnable成员函数:
void QRunnable::setAutoDelete(bool autoDelete);
设置其传到底给线程池后,是否需要自动析构;
bool QRunnable::autoDelete() const;
若该值为false,则需要程序员手动析构,要注意内存泄漏;
QThreadPool成员函数:
void QThreadPool::start(QRunnable * runnable, int priority = 0);
start() 预定一个线程用于执行QRunnable接口,当预定的线程数量超出线程池的最大线程数后,QRunnable接口将会进入队列,等有空闲线程后再执行;priority指定优先级
bool QThreadPool::tryStart(QRunnable * runnable);
tryStart() 和 start() 的不同之处在于,当没有空闲线程后,不进入队列,返回false
bool tryTake(QRunnable *runnable)
删除队列中的一个QRunnable,若当前QRunnable 未启动则返回成功,正在运行则返回失败
void setMaxThreadCount(int maxThreadCount)
设置线程池维护的最大线程数量;若没有设定,默认值是最大线程数,可以用:QThread::idealThreadCount(); 获取;
int maxThreadCount() const
获取线程池维护的最大线程数量;
int activeThreadCount() const
当前的活动线程数量
void QThreadPool::clear();
清空队列中还没有执行的QRunnable;
bool QThreadPool::waitForDone(int msecs = -1);
等待所有线程结束并释放资源, msecs指定超时;
若所有线程都被移除,则,返回true,否则返回false;
void setExpiryTimeout(int expiryTimeout)
线程长时间未使用将会自动退出节约资源
int expiryTimeout() const
获取线程的终结超时时间;
void releaseThread()
释放被保留的线程
void reserveThread()
保留线程,此线程将不会占用最大线程数量,从而可能会引起当前活动线程数量大于最大线程数量的情况
static QThreadPool * QThreadPool::globalInstance();
全局内存池实例。若创建QThreadPool实例,则在实例生存周期内,内存池有效
示例:
任务类代码如下:
class MyTask : public QObject, public QRunnable
{
Q_OBJECT
public:
MyTask();
~MyTask();
void stopTask();
protected:
void run();
signals:
//注意!要使用信号,采用QObejct 和 QRunnable多继承,记得QObject要放在前面
void mySignal();
private:
volatile bool m_stop;
};
MyTask::MyTask()
{
m_stop = false;
}
MyTask::~MyTask()
{
qDebug()<<"~MyTask()";
}
void MyTask::stopTask()
{
m_stop = true;
qDebug() << "MyTask::stopTask()" << QThread::currentThread();
}
//线程真正执行的内容
void MyTask::run()
{
int count = 0;
while(!m_stop) {
QThread::sleep(1);
if (++count >= 5) {
return;
}
}
qDebug() << "MyTask run 被调用,调用线程ID为:" << QThread::currentThread();
}
主线程使用定义:
QThreadPool m_pool;
QVector<QPointer<MyTask>> m_task; // 存放任务对象
启动:
//设置最大线程数为2的一个线程池
m_pool.setMaxThreadCount(2);
// 创建5个任务并保存对象
for (int i = 0; i < 5; i++) {
QPointer<MyTask> a(new MyTask());
m_task.append(a);
m_pool.start(a);
}
终止:
m_pool.clear();
for(int i = 0; i < m_task.size();++i){
qDebug() << m_task[i].isNull();
if (!m_task[i].isNull()) { // QPointer智能指针isNull判断指针是否有效
// m_task[i].data()->stopTask(); // 停止还在运行中的任务
}
}
m_pool.waitForDone();
qDebug()<<m_pool.activeThreadCount();
m_task中记录了任务对象,线程池默认是执行完任务后删除任务对象的,通过QPointer的IsNull()就知道哪个对象没有删除,以此判断任务是否结束;