浅谈 Qt 线程类 起点学习

移动开发
本文介绍的是理解 Qt 多线程类 起点学习,QThread 是Qt中一个对线程支持的核心的底层类。每个线程对象代表了一个运行的线程。

浅谈 Qt 多线程类 起点学习是本文要介绍的内容,不多说,先来看内容。由于Qt的跨平台特性,QThread成功隐藏了所有在不同操作系统里使用线程的平台相关性代码。

POINT 1:QThread的实例与普通的实例没什么不同,只是运行着的run()函数会不同。

例1:

  1. class MThread :public QThread   
  2. {   
  3. public:   
  4.     MThread();   
  5.     ~MThread();   
  6.     void run();   
  7.     void foo();   
  8.     ...   
  9.        
  10. };  
  11. class MDialog :public QDialog   
  12. {   
  13.     ...   
  14.     MThread *mythread;   
  15. };   
  16. MDialog::MDialog()   
  17. {   
  18.     mythread = new MThread;   
  19.     ...    

需要注意的是,在QT中,QThread对象的实例mythread是属于创建它的线程(线程A,即MDialog所在的线程)的,mythread的所有程序代码与数据都放在与MDialog相同的空间中.这时的mythread,就像任何普通的自己定义的类的实例一样.但是在调用mythread->start()之后,mythread的run()函数中的代码会在新的线程(线程B)中执行.在run()函数中声明的变量\实例化的对象,都属于线程B.

但是mythread的所有代码,都还在存储在线程A中,只是run()函数的"执行"是在线程B中.在MDialog中,使用mythread->foo();foo()是在线程A中执行的.在MDialog中使用connect(this, SIGNAL(sigDialogSignal()), mythread, SLOT(slotThreadSlot()));

当emit sigDialogSignal()时,是会在MDialog所在的线程A中执行的.因为mythread与MDialog同属于一个线程, 这时thread可以看做一个普通的实例.另外,因为connect函数的连接方式默认是自动连接,而对同属于一个纯种的两个对象,自动连接会使用直接连接,即slot在发出signal的线程中立即执行.

例2:

  1. #include "mthread.h"   
  2. #include <QDebug>   
  3. MThread::MThread(QObject *parent)   
  4.     : QThread(parent)   
  5. {   
  6.     myTimer.start(1);   
  7.     connect(&myTimer, SIGNAL(timeout()), this, SLOT(slotPrint()));   
  8. }   
  9.  
  10. MThread::~MThread()   
  11. {   
  12.  
  13. }   
  14. void MThread::run()   
  15. {      
  16.     for (int i = 0; i < 100; ++i) {   
  17.         for (int j = 0 ; j < 10000; ++j) {   
  18.             qDebug()<<"---------"<<i;   
  19.         }   
  20.     }   
  21.     exec();   
  22. }   
  23. void MThread::slotPrint()   
  24. {   
  25.     qDebug()<<"==============================";   
  26.  

运行后出现:

  1. ...   
  2. ...   
  3. ---------9   
  4. ==============================================================   
  5. ---------9   
  6. ...   
  7. ... 

不能误以为:在一个QThread类的派生类中,run()函数中的语句在运行时,可能被本线程定时器超时slot中断. (错误)

事实上,slotPrint()在创建MThread的实例的线程中执行.

POINT 2:线程B中的对象要想接收线程A中的对象发来的signal, 必须进入exec(), 如在exec()前有死循环, 没有进入exec(), 则线程B中的对象不会收到signal.

  1. void MThread::run()   
  2. {   
  3.     while(1) {   
  4.         dosomething();  //此循环永不退出   
  5.     }   
  6.     exec();             //如果此事件循环不能进入,刚此线程不会收到任何signal   

POINT 3:线程A中的指针可指向线程B中创建的对象实例,  这个实例属于线程B. 指针仅仅是一个地址, 而对象实例的变量/代码等都属于线程B.

例1:

  1. class MThread : public QThread   
  2. {   
  3.     Q_OBJECT   
  4. public:   
  5.     MThread(QObject *parent = 0);   
  6.     ~MThread();   
  7.     void run();   
  8.     MPrint *mprint;   
  9. };   
  10. void MThread::run()   
  11. {   
  12.     mprint = new MPrint;   
  13.     exec();   
  14. }   
  15. //如此声明,mprint所指向的对象属于另一个线程. 

例2:

  1. class MThread : public QThread   
  2. {   
  3.     Q_OBJECT   
  4.  
  5. public:   
  6.     MThread(QObject *parent = 0);   
  7.     ~MThread();   
  8.     void run();   
  9.     MPrint *mprint;   
  10. private:   
  11.     QTimer *myTimer;   
  12. private slots:   
  13.     void slotPrint();      
  14.     void testFoo();   
  15. };   
  16. void MThread::run()   
  17. {   
  18.     myTimer = new QTimer;   
  19.     mprint = new MPrint;   
  20.     myTimer->setInterval(100);   
  21.     connect(myTimer, SIGNAL(timeout()), this, SLOT(testFoo()), Qt::DirectConnection);   
  22.     QTimer::singleShot(0, myTimer,SLOT(start()));   
  23.     exec();   

 

上这样写run(),myTimer在run()中new,即myTimer这个指针属于旧线程,但myTimer所指向的QTimer实例的实体在新的线程中,testFoo()会在新线程中执行,例3:

  1. void MThread::run()   
  2. {   
  3.     QTimer myTimer;   
  4.     mprint = new MPrint;   
  5.     myTimer.setInterval(100);   
  6.     connect(&myTimer, SIGNAL(timeout()), this, SLOT(testFoo()), Qt::DirectConnection);   
  7.     QTimer::singleShot(0, &myTimer,SLOT(start()));   
  8.     //testFoo();   
  9.     exec();   

以上这样写run(),myTimer在run()中声明,即myTimer属于新的线程,testFoo()也会在新线程中执行,例4:

  1. class MThread : public QThread   
  2. {   
  3.     Q_OBJECT   
  4. public:   
  5.     MThread(QObject *parent = 0);   
  6.     ~MThread();   
  7.     void run();   
  8.     MPrint *mprint;   
  9. private:   
  10.     QTimer myTimer;   
  11. private slots:   
  12.     void slotPrint();      
  13.     void testFoo();   
  14. };   
  15. void MThread::run()   
  16. {   
  17.     mprint = new MPrint;   
  18.     myTimer.setInterval(100);   
  19.     connect(&myTimer, SIGNAL(timeout()), this, SLOT(testFoo()));   
  20.     QTimer::singleShot(0, &myTimer,SLOT(start()));   
  21.     //testFoo();   
  22.     exec();   

以上这样写run(),testFoo()会在创建myTimer的老线程中执行.因为可以看到,mytimer和this(即mythread),都是在同一个线程中,只是在另一个线程中(run()),做了connect操作.

要注意的是,在线程B中启动线程A中的一个定时器,不能使用myTimer.start(),这样启动不了定时器.而应使用signal来触发start()这个slot.

POINT 5:slot不会中断同线程中的slot,例1:

  1. #include "mthread.h"   
  2. #include <QDebug>   
  3. MThread::MThread(QObject *parent)   
  4.     : QThread(parent)   
  5. {   
  6.     myTimer.start(1);   
  7.     connect(&myTimer, SIGNAL(timeout()), this, SLOT(slotPrint()));   
  8. }   
  9. MThread::~MThread()   
  10. {   
  11.  
  12. }   
  13. void MThread::run()   
  14. {   
  15.     exec();   
  16. }   
  17. void MThread::slotPrint()   
  18. {   
  19.     qDebug()<<"===========================";   
  20.     for (int i = 0; i < 100; ++i) {   
  21.         for (int j = 0 ; j < 10000; ++j) {   
  22.             qDebug()<<"---------"<<i;   
  23.         }   
  24.     }   
  25. }  

slotPrint()函数运行完之后才会退出,说明slot不会中断slot,一个slot在执行完之后才会执行下一个slot.

注意:slotPrint()在创建MThread实例的线程中执行.而不是使用thread->start()创建出的那个线程,例2:

  1. #include "mthread.h"   
  2. #include <QDebug>   
  3. MThread::MThread(QObject *parent)   
  4.     : QThread(parent)   
  5. {   
  6.     myTimer.start(1);   
  7.     connect(&myTimer, SIGNAL(timeout()), this, SLOT(slotPrint()));   
  8. }   
  9. MThread::~MThread()   
  10. {   
  11.  
  12. }   
  13. void MThread::run()   
  14. {   
  15.     testFoo();   
  16.     exec();   
  17. }   
  18.  
  19. void MThread::slotPrint()   
  20. {   
  21.     qDebug()<<"=======================";   
  22.  
  23. }   
  24. void MThread::testFoo()   
  25. {   
  26.     for (int i = 0; i < 100; ++i) {   
  27.         for (int j = 0 ; j < 10000; ++j) {   
  28.             qDebug()<<"---------"<<i;   
  29.         }   
  30.     }   
  31. }  

以上代码中,slotPrint()与testFoo()会在两个不同的线程中执行.

小结:浅谈 Qt 多线程类 起点学习的内容介绍完了,希望本文对你有所帮助。更多内容请参考编辑推荐。

责任编辑:zhaolei 来源: 互联网
相关推荐

2011-07-04 16:20:54

QT 窗口 QWidget

2011-06-13 10:03:19

Qt 多线程 编程

2011-06-29 16:34:11

Qt 子线程 线程

2011-09-07 16:36:00

Qt Widget

2011-06-28 14:02:34

QT ARM

2011-06-22 15:24:50

Qt 线程

2011-06-15 10:49:26

Qt QTableItem

2011-07-04 15:43:03

Qt 布局管理器 designer

2011-06-28 15:37:34

Qt 内存

2011-06-21 16:51:21

Qt 静态 编译

2011-08-30 13:33:29

Qt数据库

2011-07-05 10:22:44

Qt Sqlite

2011-07-04 15:30:24

Qt 布局 GridLayout

2011-06-15 10:08:01

Qt CVS

2011-06-28 17:21:50

QT UI designer

2011-06-15 16:50:09

Qt 模块

2011-06-16 11:28:48

Qt QApplicati

2011-06-22 10:12:08

Qt 线程

2011-08-29 10:34:36

QTQWebKitJavaScript

2011-06-10 16:44:17

Qt 浏览器
点赞
收藏

51CTO技术栈公众号