转载Qt多线程的理解

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. };

  1. class  MDialog : public  QDialog
  2. {
  3.     ...
  4.     MThread *mythread;
  5. };
  6. MDialog::MDialog()
  7. {
  8.     mythread =  new  MThread;
  9.     ... 
  10. }
需要注意的是,在QT中,QThread对象的实例mythread是属于创建它的线程(线程A,即MDialog所在的线 程)的,mythread的所有程序代码与数据都放在与MDialog相同的空间中.这时的mythread,就像任何普通的自己定义的类的实例一样.但 是在调用mythread->start()之后,mythread的run()函数中的代码会在新的线程(线程B)中执行.在run()函数中声 明的变量/实例化的对象,都属于线程B.但是mythread的所有代码,都还在存储在线程A中,只是run()函数的"执行"是在线程B中.

在MDialog中,使用

  1. mythread->foo();

foo()是在线程A中执行的.

 

在MDialog中使用

  1. 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. MThread::~MThread()
  10. {
  11. }
  12. void  MThread::run()
  13. {   
  14.      for  ( int  i = 0; i < 100; ++i) {
  15.          for  ( int  j = 0 ; j < 10000; ++j) {
  16.             qDebug()<< "---------" <<i;
  17.         }
  18.     }
  19.     exec();
  20. }
  21. void  MThread::slotPrint()
  22. {
  23.     qDebug()<< "==============================" ;
  24. }

运 行后出现:

  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
  7. }

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. 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.     myTimer =  new  QTimer;
  18.     mprint =  new  MPrint;
  19.     myTimer->setInterval(100);
  20.     connect(myTimer, SIGNAL(timeout()),  this , SLOT(testFoo()), Qt::DirectConnection);
  21.     QTimer::singleShot(0, myTimer,SLOT(start()));
  22.     exec();
  23. }

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

 

 

connect的第五个参数用于指定反应速度:

若将:
connect(cm, SIGNAL(sendLog(QUuid, QByteArray, bool)),
            this,SLOT(sendRes(QUuid,QByteArray,bool)));
改为:
connect(cm, SIGNAL(sendLog(QUuid, QByteArray, bool)),
            this,SLOT(sendRes(QUuid,QByteArray,bool)), Qt::DirectConnection );

可解决因信号没有及时发送,致使connect的接收方的槽不能作进一步处理.

 

例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();
  10. }

以上这样写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();
  23. }

以上这样写 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. void  MThread::run()
  13. {
  14.     exec();
  15. }
  16. void  MThread::slotPrint()
  17. {
  18.     qDebug()<< "===========================" ;
  19.      for  ( int  i = 0; i < 100; ++i) {
  20.          for  ( int  j = 0 ; j < 10000; ++j) {
  21.             qDebug()<< "---------" <<i;
  22.         }
  23.     }
  24. }

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. void  MThread::run()
  13. {
  14.     testFoo();
  15.     exec();
  16. }
  17. void  MThread::slotPrint()
  18. {
  19.     qDebug()<< "=======================" ;
  20. }
  21. void  MThread::testFoo()
  22. {
  23.      for  ( int  i = 0; i < 100; ++i) {
  24.          for  ( int  j = 0 ; j < 10000; ++j) {
  25.             qDebug()<< "---------" <<i;
  26.         }
  27.     }
  28. }

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

你可能感兴趣的:(thread,多线程,object,存储,qt,Signal)