【c++】 小白科普向——使用QThread和C++实现多线程(一个UI界面线程,多个子线程)

目录

【一】类的架构设计

【二】通过QObject实现多线程

【三】界面的显示和按钮事件


先放一篇写的很好理解的文章~~~

https://blog.csdn.net/czyt1988/article/details/71194457

本文的代码的功能: 画一个界面,显示界面的时候,同时开启几个子线程, 子线程返回自己的线程ID号,并且在界面上显示出来。

 

【一】类的架构设计

一开始接触多线程,完全不知道怎么设计类。 

我看了一些相关的代码之后,大家的程序都差不多,大概的程序构架是这样的:

|-----------------------------------------VS2017工程--------------------------------------------

|----------------程序入口                             main.cpp 

|---------------UI类头文件                          UI.h

|---------------UI类成员函数实现               UI.cpp

|---------------线程类头文件                       thread.h

|---------------线程类成员函数实现            thread.cpp

 

它们之间的关系,或者说我的代码实现流程大体是这样的:

(1)调用main函数。

main函数就干了一件事儿:构造了一个UI类的对象出来,然后显示。

 

========================备注备注备注备注====================================

在使用QT自动生成代码的时候,自动生成cpp文件或者h文件里面的实际上是一个类。有时候我又想改界面,再重新生成一个全新的cpp文件。所以我希望我实现一些功能的时候(比如添加某个按钮的信号和槽),不是在这个cpp文件里改动,否则一旦界面改动,我之前实现的功能就被QT自动生成的代码改掉了。

【实现方式】我自己写了一个UI类,QT生成的类是我的UI类的成员变量,也就是我在我的UI类里构造了一个对象出来。

详情见代码。

========================备注完了备注完了备注完了=============================

 

(2)开启多个线程。

线程在哪里实现嘞?main函数构造UI对象。这个过程调用了UI类。UI类有一个【开启线程】的成员函数。

这个【开启线程】函数会通过【线程数组】实例化一大堆线程出来,也就是开启多个线程。(这里涉及到一些槽和信号的连接,在后面中详细说。)

(3)线程开始工作。

实例化线程。主线程,也就是我的UI类,会通过emit方法让子线程开始工作。子线程开始干活,干完活儿再通过emit方法把结果给主线程。

 

放上两个类的定义的代码:

===线程类=====

#ifndef GGTHREAD_H
#define GGTHREAD_H
#include 

class ggClassThread: public QObject
{
	Q_OBJECT
public:
	ggClassThread(QObject* parent = NULL);
	~ggClassThread();

signals:
	void message(const QString& info);

public slots:
	void runSomeBigWork1();
};

#endif // !GGTHREAD_H

====UI类===

#ifndef GGCLASSUI_H
#define GGCLASSUI_H

# include "ggUI_V1.h"
# include "ggThread.h"
#include 

class ggClassUi: public QWidget {
	Q_OBJECT
public:
	ggClassUi();
	ggClassUi(QMainWindow	*win);
	~ggClassUi();
	void outPutInfo(QString info);
	void startThread();

private:
	Ui_ggUI_V1Class ggUi;
	ggClassThread*	ggThread[4];
	QThread*        ggQthread[4];

signals:
	void startThreadWork();

public slots:
	void on_startSever_clicked();
};

#endif // GGCLASSUI_H

结合代码,流程大概就是:

(1)【main】------(实例化界面)-----》(2)【UI】---------(按钮按下的信号触发函数on_startServer_clicked,调用startThread()实例化线程)------》(3)【thread】-----------(通过信号startThreadWork,触发线程工作函数runSomeBigWork1, 线程工作结束,message函数触发outPutInfo显示结果)------》(4)【UI】显示结果

 

【二】通过QObject实现多线程

实现多线程的方式挺多的,这里主要是通过QObject实现多线程。

最关键的函数是:moveToThread()。 

要了解这个函数,首先从多线程说起,QThread类是Qt多线程实现的基础。我们先一个实例化出来一个Qthread对象,在实例化我们自己定义的一个【实现某个功能】的类,这个时候,使用moveToThread函数,就能让这个功能在Qthread创建的线程里运行了。实际上是把一个普通的类的函数换了个地方执行,从而实现了多线程。

void ggClassUi::startThread() {
    for (int i = 0; i < 4; i++) {
        ggQthread[i] = new QThread(); //Qthread
        ggThread[i] = new ggClassThread(); //普通的类
        ggThread[i]->moveToThread(ggQthread[i]); //移到线程里执行
        connect(ggQthread[i], &QThread::finished, ggQthread[i], &QObject::deleteLater);
        connect(ggQthread[i], &QThread::finished, ggThread[i], &QObject::deleteLater);// 【1】
        connect(this, &ggClassUi::startThreadWork, ggThread[i], &ggClassThread::runSomeBigWork1);//【2】
        connect(ggThread[i], &ggClassThread::message, this, &ggClassUi::outPutInfo);//【3】
        ggQthread[i]->start();
    }
}

为了换地方,需要建立一些联系,通过connect函数来完成。

注释【1】Qthread结束, 类要delete

注释【2】startThreadWork被调用(这个函数里创建了一些Qthread对象出来),实际上是线程开始执行,触发自定义的线程类开始工作。

注释【3】工作结束,message函数会触发界面的outPutInfo函数。

【三】界面的显示和按钮事件

初始化界面的时候,把界面上【开启线程】的按钮,通过clicked信号,连接到自己写的槽函数上,来开启线程。

ggClassUi::ggClassUi(QMainWindow	*win) {
	ggUi.setupUi(win);
	connect(ggUi.startServerButton, &QPushButton::clicked, this, &ggClassUi::on_startSever_clicked);
}

void ggClassUi::on_startSever_clicked() {
	startThread();
	emit startThreadWork();
	ggUi.startServerButton->setEnabled(false);
}

在通过startThread开启线程后,emit发出信号startThreadWork,线程就开始工作了。

 

你可能感兴趣的:(c++,c++,多线程,UI,Qthread)