Qt基础开发之Qt多线程类QThread与Qt定时器类QTimer的详细方法与实例

Qt基础开发之Qt多线程类QThread与Qt定时器类QTimer的详细方法与实例

本文主要介绍Qt基金会开发的Qt多线程类Qt QThread和Qt timer类Qt Timer的具体方法和实例。有需要的可以参考以下。

Qt多线程

我们之前的程序都是单线程的,后来开始引入多线程。相当于以前一个人工作,现在很多人一起工作。

在Qt中使用多线程是非常必要的,因为Qt应用是事件驱动的,一旦一个事件处理程序耗时过长,其他事件就无法及时处理。

Qt使用QThread来管理线程。QThread对象是一个线程。QThread对象还有一个message sequential exec()函数,用于处理自己线程的事件。

Qt实现多线程有两种方式

1.Qt是创建线程的第一种方式

首先继承QThread

重写虚函数QThread:run

[虚拟保护] void QThread:run()

/*

*基类QThread的run函数只是启动exec()消息循环。

*/

例如:

#包括QApplication

#包含QThread

#包含QDebug

类MyThread:公共QThread

{

公共:

无效运行()

{

qDebug()“q thread begin”endl;

qDebug()“子线程”QThread:current threadid()endl;

q thread:sleep(5);

qDebug()“q thread end”endl;

exec();

}

};

int main(int argc,char** argv)

{

QApplication app(argc,argv);

MyThread线程;

thread . start();

qDebug()“主线程”QThread:current threadid()endl;

q thread:sleep(5);

qDebug()“主线程”QThread:current threadid()endl;

thread . quit();

qDebug()主线程thread . quit() endl;

tread . wait();

qDebug() main thread thread . wait() endl;

返回app . exec();

}

使用QThread的quit可以退出线程的消息循环。有时候不会马上退出,需要等到cpu的控制权回到线程的exec()上。

一般来说,当一个子线程退出时,主线程需要回收资源。可以调用QThread的wait,等待子线程退出,然后回收资源。

2、Qt第二种创建线程方式

继承QObject

实例化一个QThread对象

实现插槽功能。

QObject子类对象通过移动到thread将自己放入thread QThread对象中。

调用QThread对象的start函数启动线程。

slot函数必须通过发送信号在线程中执行,发送的信号存储在线程exec()消息队列中。

例如:

mywork.h

#ifndef MYWORK_H

#定义我的工作_H

#包含QThread

#包含QDebug

类MyWork:公共QObject

{

q _对象

公共插槽:

无效工作批次()

{

qDebug()“q thread begin”endl;

qDebug()“子线程”QThread:current threadid()endl;

q thread:sleep(5);

qDebug()“q thread end”endl;

}

};

#endif //MYWORK_H

widget.cpp

#包括QApplication

#包含QThread

#包含QDebug

#包含“mywork.h”

int main(int argc,char** argv)

{

qDebug()“主线程”QThread:current threadid()endl;

QApplication app(argc,argv);

QThread线程;

我的工作;

work.moveToThread(线程);

QObject:connect(thread,SIGNAL(started()),work,SLOT(work SLOT()));

thread . start();

q thread:sleep(6);

“qDebug()”线程正在运行“thread . is running()endl;

thread . quit();//调用quit使线程退出消息循环,否则线程将一直处于exec循环中。

thread . wait();//调用quit后立即调用wait回收线程资源。

“qDebug()”线程正在运行“thread . is running()endl;

返回app . exec();

}

应特别注意:

slot函数已经执行并进入线程exec()。您可以通过发送信号在线程中重新执行插槽函数。您也可以通过quit()退出线程exec()。

将调用moveToThread的QObject派生类对象不能指定主线程父对象托管内存。

QWidget和派生类对象的对象只能在GUI主线程中运行,不能使用moveToThread移动到子线程,即使没有指定父对象。

多线程对象内存释放

既然QObject对象不能托管内存对象,我们应该先释放线程对象还是QObject对象?

首先在线程循环中释放QObject(使用QObject:deleteLater函数),然后是QThread:quit,然后是QThread:wait。

例如:

mywork.h

#ifndef MYWORK_H

#定义我的工作_H

#包含QThread

#包含QDebug

类MyWork:公共QObject

{

q _对象

公共:

~ my work(){ qDebug()_ _ FUNCTION _ _ endl;}

公共插槽:

无效工作批次()

{

while(1)

{

qDebug() Work begin endl;

q thread:sleep(5);

qDebug()“work end”endl;

}

}

void otherWorkSlot()

{

qDebug()“other work begin”endl;

q thread:sleep(5);

qDebug()“other work end”endl;

}

};

#endif //MYWORK_H

widget.h

#ifndef WIDGET_H

#定义WIDGET_H

#包含QWidget

#包含“mywork.h”

类小部件:公共QWidget

{

q _对象

公共:

widget(q widget * parent=0);

~ Widget();

私人:

QThread * _ thread

MyWork * _ myWork

};

#endif //WIDGET_H

widget.cpp

#include widget.h

#包括q按钮

#包含“mywork.h”

#包含QThread

#包含QHBoxLayout

Widget:Widget(QWidget *parent)

:QWidget(父级)

{

_myWork=新my work;

_ thread=new q thread(this);

_ my work-moveToThread(_ thread);

_ thread-start();

q push button * pb0=new q push button( work ,this);

QPushButton *pb1=新的QPushButton(pb ,this);

qhbox layout * hBox=new qhbox layout(this);

hBox-add widget(pb0);

hBox-add widget(PB1);

this-set layout(hBox);

/*向另一个线程中的对象队列发送信号*/

connect(pb0,SIGNAL(clicked()),_myWork,SLOT(work SLOT()));

connect(pb1,SIGNAL(clicked()),_myWork,SLOT(otherWorkSlot()));

/*释放内存的建议用法*/

//connect(_thread,SIGNAL(finished()),_myWork,SLOT(delete later());

}

Widget:~Widget()

{

_ my work-delete later();//确保在QThread线程退出之前

_thread-quit()。

_thread-wait()。

}

3、Qt线程的同步

当多个线程同时访问一个资源时(例如,可以被多个线程操作的变量和函数等。),谁来使用这个资源是个问题。就像一大群人在抢同一个蛋糕。可能其中一个抢了,蛋糕被砸的可能性更大。在多线程中,这被称为竞争冒险。然后我们需要设置一个规则来约束大家,比如大家排队去拿蛋糕,这在多线程中叫同步法。

需要注意的是,同步不是同时的,而是有序的。

3.1、互斥锁

Qt中的互斥体是QMutex,它不继承任何Qt基类。它使用QMutex来锁定共享资源。谁拿到钥匙,谁就有权利使用这个资源。其他线程会等待这个线程用完资源并返回密钥,然后它们会获取密钥。

例如:

QMutex互斥体;//此对象通常定义在多线程可以访问它的地方。

mutex . lock();//多个线程调用此函数获取锁。没有获得它的线程将阻塞并等待这个函数。

mutex . unlock();//释放锁定

qmtex: lock函数将让线程等待获取锁。如果不想等待,可以使用函数:

bool q mutex:try lock(int time out=0)

/*

*参数int timeout:等到超时毫秒,无论是否获取锁都会返回。超时为0时,直接返回。

*返回值true表示获取了锁,false表示没有获取。

*/

有时候我们会忘记释放锁,Qt也给我们提供了一个类QMutexLocker来管理锁。

QMutex互斥体;

void函数()

{

QMutexLocker锁(_ mutex);//最好将//QMutexLocker实例化为stack对象,在释放之前解锁QMutex。

}

在上面的例子中,一旦func()被执行,locker被自动释放,那么在释放它之前先解锁它。

3.2、信号量

只有一个线程可以同时获得使用受互斥体保护的资源的权利。有些资源可以被多个线程同时访问,所以此时可以使用信号量。在Qt中,信号量是QSemaphore。

QSemaphore sem(2) //初始化信号量是2

SEM . acquire();//信号量位为0时,调用此函数会使信号量-1。一旦信号量为零,它将阻塞等待。

semaphore.release()。//制作信号量1

4、Qt定时器QTimer

定时器可以每隔一段时间发送一次信号,通过接收这个信号来处理一些定时任务。应该注意的是,计时器不会启动新的线程。Qt中的定时器由Qt Timer从QObject继承而来。

通过QTimer:start()启动定时器

无效开始时间(毫秒)

/*

*定时毫秒(毫秒)毫秒后,发射超时()信号

*/

通过链接信号超时()来处理一些定时任务,例如:

#include dialog.h

#包含QTimer

#包含qdebug.h

Dialog:Dialog(QWidget *parent)

:QDialog(父)

{

q timer * timer=新q timer(this);

connect(timer,SIGNAL(timeout()),this,SLOT(do something());

定时器-启动(3000);

}

空的对话框* do something()

{

qDebug()_ _ FUNCTION _ _ endl;

}

对话框:~对话框()

{

}

本文主要介绍了夸脱多线程类q线程与夸脱定时器类QTimer的详细方法与实例,更多关于夸脱开发知识请查看下面的相关链接

Qt基础开发之Qt多线程类QThread与Qt定时器类QTimer的详细方法与实例