************************************************************
author: hjjdebug
date: 2024年 02月 03日 星期六 11:23:29 CST
description: QT中QThread, QTimer的使用
目的: 用最简单的程序
1. 了解QT编程的框架
2. 了解QThread 对象的使用
3. 了解QTimer 对象的使用
************************************************************
要求1. 实现一个程序,每1秒钟打印一个数,从1打印到9.
----------------------------------------
1. 非qt的程序,
----------------------------------------
#include <stdio.h>
int main()
{
for(int i=i;i<10;i++)
{
printf("data is %d\n",i);
sleep(1);
}
return 0;
}
----------------------------------------
2. qt程序的实现。
----------------------------------------
2.1: 首先, qt程序是有一个框架的,它的主流程是这样的。
int main(int argc,char *argv[])
{
QApplication *app=new QApplication(argc,argv);
....
return app->exec();
}
你的while循环或者for 循环不能放到主线程中,只能放到其它线程中
因为主线程是负责消息分发的.
下面看看把一个for 循环或while循环放到一个线程中的解决方法。
------------------------------------------------------------
2.2: 把循环用传统的c调用接口 pthread_create 创建线程来实现
------------------------------------------------------------
以下程序均编译通过.
#include <QApplication>
#include <unistd.h>
void *thread_routine(void *)
{
for(int i=1;i<10;i++)
{
printf("data is %d\n",i);
sleep(1);
}
return 0;
}
int main(int argc,char *argv[])
{
QApplication *app=new QApplication(argc,argv);
pthread_t threadid;
pthread_create(&threadid,NULL,thread_routine,NULL);
printf("threadid:%ld\n",threadid);
return app->exec();
}
运行结果:
./test_thread_qt
threadid:139793910314752
data is 1
data is 2
data is 3
data is 4
data is 5
data is 6
data is 7
data is 8
data is 9
用pthread_create 来创建线程很简洁,挺好的.
但QT又自己实现了一套机制,用Qt的QTread 显得更本土化,它是c++接口,面向对象的,如下:
----------------------------------------
2.3 把循环用QThread线程来实现
----------------------------------------
#include <QApplication>
#include <unistd.h>
#include <QThread>
class CMyThread : public QThread
{
public:
CMyThread(){}
~CMyThread(){}
void run(void ) override // 重写run 函数
{
pthread_t threadid=gettid();
printf("sub threadid:%ld\n",threadid);
for(int i=1;i<10;i++)
{
printf("data is %d\n",i);
sleep(1);
}
}
};
int main(int argc,char *argv[])
{
QApplication *app=new QApplication(argc,argv);
CMyThread *myThread = new CMyThread(); //创建了一个QThread 对象,这个对象是QThread的继承类
myThread->start();
pthread_t threadid=gettid();
printf("main threadid:%ld\n",threadid);
return app->exec();
}
编程架构说明:
1. 主线程中,创建一个CMyThread 对象,继承自QThread, 它复写了QThreadd 的run 函数.
面向对象的编程方法.
然后调用对象的start()
即可实现子进程的运行
然后你要完善生成对象的类。
下面是执行结果:
./test_thread_qt
main threadid:5583
sub threadid:5589
data is 1
data is 2
data is 3
data is 4
data is 5
data is 6
data is 7
data is 8
data is 9
----------------------------------------
2.4: 把sleep() 函数用QTimer 来实现.
----------------------------------------
sleep 调用就是最简单的,为什么要用QTimer?
是的,这里是为了演示QTimer 的用法,看一看如何用一个复杂的架构来实现.
因为当一个任务很复杂时,必须要拆分为更精细的部分加以控制.
创建一个QTimer 对象,1秒钟定时,时间到会回调用户程序,完成i加法和打印
用了QTimer, 就不用QThread 对象了, 因为QTimer的回调就在一个线程中.
但是根据c++的面向对象的编程方法,我们还是要创建一个对象,QT中能够使用消息
的对象都是继承自QObject, 这里的实现是创建了一个CMyObject 类,该类包含一个QTimer对象
下面是完整代码, 主线程中还是创建object,然后再启动timer就可以了
主函数main.cpp 还是那么简单.
$ cat main.cpp
#include <QApplication>
#include "myObject.h"
int main(int argc,char *argv[])
{
QApplication *app=new QApplication(argc,argv);
CMyObject *myObj = new CMyObject(); // Qt中的对象都是QObject的子对象
myObj->start();
pthread_t threadid=gettid();
printf("main threadid:%ld\n",threadid);
return app->exec();
}
myObject.h 必须要分开独立写了,因为它包含了Q_OBJECT 宏, 该宏是收发消息所必须的,
有了该宏,QT 就会调用moc 工具从 myObject.h 生成moc_myObject.cpp
如果把它放到main.cpp中而不单独拉出一个.h头文件,就无法生成moc_*.cpp 文件,最后会有连接错误,
如下:
undefined reference to `vtable for CMyObject'
下面附上完整的myObject.h 和myObject.cpp 代码
$ cat myObject.h
#include <QObject>
#include <QTimer>
#include <unistd.h>
class CMyObject : public QObject
{
Q_OBJECT
public:
CMyObject(QObject *parent=nullptr) : QObject(parent)
{
m_timer = new QTimer();
connect(m_timer,SIGNAL(timeout()),this,SLOT(slotTimeout()));
}
~CMyObject(){}
void start()
{
m_timer->start(1000); //启动timer,1秒时间到
}
private slots:
void slotTimeout(void ) //时间到后的槽函数
{
pthread_t threadid=gettid();
printf("sub threadid:%ld\n",threadid); //发现timerID 与主线程ID 是一样的,就是同一个线程
m_i++;
printf("data is %d\n",m_i);
if(m_i==9) // 何时退出循环,清理现场,需要判断
{
disconnect(m_timer,SIGNAL(timeout()),this,SLOT(slotTimeout()));
delete m_timer;
m_timer=NULL;
}
}
private:
QTimer *m_timer; // 该类中包含了一个QTimer 对象
int m_i=0;
};
$ cat myObject.cpp
#include "myObject.h"
下面是其执行结果:
$ ./test_qtimer
main threadid:8374
sub threadid:8374
data is 1
sub threadid:8374
data is 2
sub threadid:8374
data is 3
sub threadid:8374
data is 4
sub threadid:8374
data is 5
sub threadid:8374
data is 6
sub threadid:8374
data is 7
sub threadid:8374
data is 8
sub threadid:8374
data is 9
可见timer slot 函数线程ID 就是主线程ID