一.未使用多线程,则w0先运行完后,w1才开始运行

运行结果(GIF动图):

main.cpp

xiaowen_QT_day29.pro

QT+=widgets
SOURCES += \main.cpp

main.cpp

#include<QApplication>
#include<QDebug>
#include<QThread>
class Work
{public:Work(const QString& name):_objectName(name){}void working(){for(int i=0;i<5;i++){qDebug()<<"working"<<_objectName<<i<<endl;QThread::sleep(1);//1秒打印1次}}
private:QString _objectName;
};int main(int argc,char** argv)
{QApplication app(argc,argv);Work w0("w0"),w1("w1");w0.working();w1.working();return app.exec();
}

二.QT中第一种创建线程的方式——派生QThread类。

2.1 这里先注释掉前部分代码,运行单独的派生QThread类WorkThread:

main.cpp

运行结果(GIF动图):

2.2 撤销前半部分的注释,尝试运行两个线程:

main.cpp

运行结果(GIF动图):

2.3 线程ID打印:

main.cpp

运行结果(GIF动图):

2.4 打印线程运行状态、回收线程:

main.cpp

运行结果:

2.5 线程中exec的问题:


main.cpp

运行结果(GIF动图):

2.6 附代码:

xiaowen_QT_day29

QT+=widgets
SOURCES += \main.cpp

main.cpp

#include<QApplication>
#include<QDebug>
#include<QThread>class Work
{public:Work(const QString& name):_objectName(name){}void run(){working();}void working(){for(int i=0;i<10;i++){qDebug()<<"working"<<_objectName<<i<<QThread::currentThreadId()<<endl;QThread::sleep(1);//1秒打印1次}}
private:QString _objectName;
};class WorkThread:public QThread
{public:WorkThread(const QString& name,QObject *parent=NULL):QThread(parent),_objectName(name){}void run(){working();this->exec();}void working(){for(int i=0;i<10;i++){qDebug()<<"working"<<_objectName<<i<<QThread::currentThreadId()<<endl;QThread::sleep(1);}}
private:QString _objectName;
};int main(int argc,char** argv)
{QApplication app(argc,argv);Work w0("w0");WorkThread w1("w1");w1.start();qDebug()<<"thread is running"<<w1.isRunning()<<endl;//打印线程运行状态w0.working();qDebug()<<"thread is running"<<w1.isRunning()<<endl;//打印线程运行状态w1.quit();qDebug()<<"thread wait finish"<<w1.wait(5000)<<endl;//打印线程运行状态return app.exec();
}

三.QT中第二种创建线程的方式

  1. 继承 QObject
  2. 实例化一个QThread对象
  3. 实现槽函数.
  4. QObject子类对象通过moveToThread将自己放到线程QThread对象中.
  5. 调用QThread对象的start函数启动线程
  6. 必须通过发射信号来让槽函数在线程中执行,发射的信号存放在线程exec()消息队列中。

例:

test.h

#ifndef TEST_H
#define TEST_H
#include <QThread>
#include <QDebug>
class MyWork : public QObject
{Q_OBJECT
public slots:void workSlot(){qDebug() << "QThread begin" << endl;qDebug() << "child thread" << QThread::currentThreadId() << endl;QThread::sleep(5);qDebug() << "QThread end" << endl;}
};
#endif // TEST_H

main.cpp

#include<QApplication>
#include<QDebug>
#include<QThread>
#include"test.h"
int main(int argc, char** argv)
{qDebug() << "main thread" << QThread::currentThreadId() << endl;QApplication app(argc, argv);QThread thread;MyWork work;work.moveToThread(&thread);QObject::connect(&thread, SIGNAL(started()), &work, SLOT(workSlot()));thread.start();QThread::sleep(6);qDebug() << "thread is runing" << thread.isRunning() << endl;thread.quit(); //调用quit让线程退出消息循环,否则线程一直在exec循环中thread.wait(); //调用完quit后紧接着要调用wait来回收线程资源qDebug() << "thread is runing" << thread.isRunning() << endl;return app.exec();
}

运行结果(GIF动图):

需要特别注意的是:

  1. 子线程中的槽函数已经执行完进入线程exec()中,可以通过发射信号重新让槽函数在线程中执行。也可以通过quit()退出线程exec()。

  2. QObject派生类对象,若要调用moveToThread,不能指定一个主线程父对象托管内存。

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

  4. 多线程对象内存释放:

      既然QObject对象无法托管内存对象,那么到底是先释放线程对象,还是先释放这个QObject对象?

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

    例:

mywork.h

#ifndef MYWORK_H
#define MYWORK_H
#include <QThread>
#include <QDebug>
class MyWork : public QObject
{Q_OBJECT
public:~MyWork() { qDebug() << __FUNCTION__ << endl; }
public slots:void workSlot(){qDebug() << "Work begin" << QThread::currentThreadId() << endl;QThread::sleep(2);qDebug() << "work end" << endl;}void otherWorkSlot(){qDebug() << "otherWork begin" << QThread::currentThreadId() << endl;QThread::sleep(2);qDebug() << "otherWork end" << endl;}
};
#endif // MYWORK_H

widget.h

#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include "mywork.h"
class Widget : public QWidget
{Q_OBJECT
public:Widget(QWidget *parent = 0);~Widget();
private:QThread *_thread;MyWork *_myWork;
};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include <QPushButton>
#include "mywork.h"
#include <QThread>
#include <QHBoxLayout>
Widget::Widget(QWidget *parent): QWidget(parent)
{_myWork = new MyWork;_thread = new QThread(this);_myWork->moveToThread(_thread);_thread->start();QPushButton *pb0 = new QPushButton("work", this);QPushButton *pb1 = new QPushButton("pb", this);QHBoxLayout *hBox = new QHBoxLayout(this);hBox->addWidget(pb0);hBox->addWidget(pb1);this->setLayout(hBox);/*发射信号给在另外一个线程的对象的队列中*/connect(pb0, SIGNAL(clicked()), _myWork, SLOT(workSlot()));connect(pb1, SIGNAL(clicked()), _myWork, SLOT(otherWorkSlot()));/*推荐用法释放内存*///connect(_thread, SIGNAL(finished()), _myWork, SLOT(deleteLater()));
}
Widget::~Widget()
{_myWork->deleteLater(); //一定要在QThread线程退出之前_thread->quit();_thread->wait();
}

main.cpp

#include "widget.h"
#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;w.show();return a.exec();
}

运行结果(GIF动图):

QT每日一练day29:QT中的多线程探究相关推荐

  1. QT每日一练day4:ubuntu中使用QT

    (本文主要是为了说明QT的跨平台特性)   一.安装QT sudo apt-get install qt5-default qtcreator cmake 二.打开QT 可以点击图标或命令行方式: 三 ...

  2. QT每日一练day1:第一个程序

    参考博文:Qt常见类.窗口类继承关系树图 QT每日一练(1):第一个程序 最终效果(GIF动图): step1: step2: step3: step4: step5: step6: step7: s ...

  3. QT每日一练day26:绘制图片

    一.第一阶段 发现上述图片没有显示全!!!!! 二.第二阶段 设置宽高比,平滑转换 运行结果(GIF动图): 发现上述图片在数次缩放后会产生失真!!!!! 三.第三阶段 为了避免图像缩放过程中产生失真 ...

  4. QT每日一练day21:鼠标事件

    一.第一阶段--鼠标点击和释放事件 运行结果(GIF动图): MouseEvent.pro #------------------------------------------------- # # ...

  5. QT每日一练day5:QLabel和按钮窗口打印功能

    运行:输入字符串然后按print按钮 project.pro QT+=widgets HEADERS += \widget.hSOURCES += \widget.cpp \main.cpp widg ...

  6. QT每日一练day2:day1优化以及QT内存管理机制

    QT中的继承关系 day1优化   一般我们不直接用QWidget来实例化对象,用它的派生类来生成对象,main函数中一般不写太多代码,都是在派生类的构造函数中进行窗口的初始化.布局.设置.其子窗口设 ...

  7. QT每日一练day27:绘制不规则窗体

    注:本文本来应该是以一个不规则的图片作为历程的,,忘记了!!!!     一.第一阶段:隐藏窗体框架 运行结果(GIF动图): widget.cpp 二.第二阶段:将窗口设置为透明 运行结果(GIF动 ...

  8. QT每日一练day25:触发绘画事件

    运行结果(GIF动图): widget.cpp 附代码: xiaowen_QT_day25.pro QT += core guigreaterThan(QT_MAJOR_VERSION, 4): QT ...

  9. QT每日一练day24:绘画事件

    一.第一阶段 设置线条粗细 二.第二阶段:设置笔的样式 如:虚线 三.第三阶段:绘制矩形 四.第四阶段:设置颜色 轮廓颜色 笔刷颜色 笔刷样式 五.第五阶段:绘制其他形状图像和文字 六.第六阶段:图像 ...

最新文章

  1. 使用代理网络配置maven,显示导入失败的原因
  2. NHibernate+MySql (erro 解决方法)
  3. Django中一个项目使用多个数据库(原生sql 的使用,亲测)
  4. SQLite大漏洞!所有Chromium浏览器中招,安卓iOS应用也受殃及
  5. android之日志库logger
  6. mysql 复杂类型_MySQL 复杂数据类型之JSON数据
  7. 计算机专业新手博客,【转载】学计算机必读献给计算机专业大一新生(1)
  8. Qpython 获取Android gps信息
  9. hdu acm1157
  10. C语言实现SM4加解密
  11. 14个PLC入门基础知识
  12. awd的批量脚本 pwn_记一次AWD反杀之旅
  13. 100 offer:为什么你不需要做一名全栈工程师?
  14. 西游记中揭示的深刻人生哲理
  15. 深大校园网掉线/Drcom掉线/使校园网保持在线V2.0+Linux端Drcom登录方法(宿舍区教学区)
  16. 苹果wifi网速慢怎么办_家里网速慢如何解决 提高WiFi网速方法【详解】
  17. 计算机or笔记本,笔记本or台式机 这几款戴尔主机性能上没得挑
  18. 如何投资股票型基金?什么时间买?买什么?
  19. IPD电源REL-70-4006
  20. ios-自定义Storyboard与UIViewController

热门文章

  1. PGSQL-通过SQL语句来计算两个日期相差的天数
  2. 基于JAVA+SpringMVC+MYSQL的医院分诊挂号管理系统
  3. 基于JAVA+SpringMVC+Mybatis+MYSQL的音乐播放系统
  4. dev下没有ttyusb_Dev C++ 软件安装教程
  5. MySQL可以用localhost 连接,但不能用IP连接的问题
  6. javascript的数据检测总结
  7. [OS] 死锁相关知识点以及银行家算法详解
  8. jQuery hover事件
  9. linux添加用户、权限
  10. DRBD安装配置、工作原理及故障恢复