一个进程里可以有多个子线程,但只能有一个主线程(也有就main开始执行的线程).
主线程退出,其它所有的子线程会随着进程结束而结束,
QT进程的主线程其实就管理窗口的事件处理,当在窗口对象的函数里做死循环或耗时比较久的事情时,会引发界面不响应的状况。所以为了不让用户抓狂,耗时的工作就放在子线程里完成。
Qt里创建子线程有两种方法:
1 封装一个继承QThread的类,并实现虚函数run. 在run函数里写上此线程所作的工作.
class MyThread : public QThread {
public:
void run() {
//做线程要作的事情
//此函数执行结束,线程也就退出工作了。所以这个函数通常都是个循环。
}
};
创建子线程对象时:
MyThread * t = new MyThread;
t->start(); //注意不是直接调用run函数,run函数是在线程启动后自动调用的。
//调用start函数时,也可以指定线程的优先级别
线程对象与窗口对象通信时,需通过信号与槽的方法。
如实现:
在窗口里点击按钮时,创建出一个子线程并分配它的ID号, 此线程每隔5秒产生一个随机数,并传递给窗口对象(也就发出信号给窗口对象).
mywin.h
#ifndef MYWIN_H
#define MYWIN_H
#include <QWidget>
#include <QPushButton>
#include <QThread>
class MyThread : public QThread
{
Q_OBJECT
private:
int id;
public:
MyThread(int id); //创建线程对象时需分配ID
void run(); //线程要做的事情
signals:
void valGot(QString); //线程的信号
};
//测试线程的窗口
class MyWin : public QWidget
{
Q_OBJECT
private:
QPushButton *btn;
QList<MyThread *> list; //用于存放线程对象地址的链表
public:
explicit MyWin(QWidget *parent = 0);
~MyWin();
signals:
public slots:
void slot_btn(); //用于连接按钮的信号
void slot_thread(QString str); //用于连接线程对象的信号
};
#endif // MYWIN_H
mywin.cpp
#include "mywin.h"
#include <QDebug>
MyThread::MyThread(int id)
{
this->id = id;
}
void MyThread::run()
{
int n;
QString str("id=%1 : val=%2");
while (1)
{
sleep(3);
n = qrand()%100; //取100内的随机数
emit valGot(str.arg(id).arg(n));
}
}
///////////////////
MyWin::MyWin(QWidget *parent) : QWidget(parent)
{
btn = new QPushButton("new thread", this);
connect(btn, SIGNAL(clicked(bool)), this, SLOT(slot_btn()));
resize(320, 240);
}
MyWin::~MyWin()
{
delete btn;
//窗口对象退出时,把所有的子线程对象结束工作并回收资源。
for (int i = 0; i < list.size(); i++ )
{
list.at(i)->terminate(); //终止线程对象的工作
list.at(i)->wait(); //回收线程对象的资源
}
}
void MyWin::slot_btn()
{
static int id = 0; //用于分配线程的ID
MyThread *t;
t = new MyThread(id++);
//连接线程对象的信号, 当线程对象的信号发出时,触发槽slot_thread
connect(t, SIGNAL(valGot(QString)), this, SLOT(slot_thread(QString)));
list.append(t); //把创建出来的线程对象的地址存入链表
t->start(QThread::LowPriority); //启动线程,并指定此线程的优先级别比一般的线程要低
}
void MyWin::slot_thread(QString str)
{
qDebug() << str; //输出线程对象发出的参数
}
main.cpp
#include <QApplication>
#include "mywin.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyWin win;
win.show();
return a.exec();
}
2 第二种的方法有点像java里实现线程的接口。
首先还是封装一个类,要求必须继承QObject类或它的派生类。其实QT里QObject是所有类的基类,也就是说基本上只要继承一个QT里的类就可以了。
然后必须实现一个槽函数,函数名随便。如:
class MyThread : public QObject
{
Q_OBJECT
public slots:
void myslot();//函数里做线程处理的事件
}
创建MyThread对象后, 还是需要一个QThread对象来处理事情
MyThread *t = new MyThread;
QThread *thread = new QThread;
t->moveToThread(thread); //指定由线程对象thread来处理。
//然后再把一个信号连接到MyThread的槽函数myslot
thread->start(); //最后启动线程