zoukankan      html  css  js  c++  java
  • Qt多线程学习-用例子来理解多线程(转),这个是我看过最好的文章,总结很详细(感觉exec()的作用就是保持线程不退出,这样方便随时处理主线程发来的信号,是一种非常别致的思路)good

    [html] view plain copy
     
    1. 01 class MThread :public QThread    
    2. 02 {    
    3. 03 public:    
    4. 04     MThread();    
    5. 05     ~MThread();    
    6. 06     virtual void run();    
    7. 07     void foo();    
    8. 08     ...    
    9. 09          
    10. 10 };  

    写在开头的话:本来查看的原文是转载,但是原文给的链接已经失效不知什么情况,自行google标题后在ChinaUnix发现同样的文章没有标注转载字样,不知是否原创,暂时贴ChinaUnix帖子里的链接吧,如有冒犯请原创者联系我,进行修改。
    (不确定是否为原文链接):http://bbs.chinaunix.net/thread-3642263-1-1.html
    实例代码1:
     
    POINT 1:QThread类的实例与普通类的实例没什么不同,只是运行着的run()函数会不同(自己注:run中的内容会在另外的线程中运行)
     
    实例代码2:
     
    01 class MDialog :public QDialog  
    02 {  
    03     ...  
    04     MThread *mythread;  
    05 };  
    06 MDialog::MDialog()  
    07 {  
    08     mythread = new MThread;  
    09     ...   
    10 }

    需要注意的是,在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的线程中立即执行.
     
    实例代码3:
     
     
    01 #include "mthread.h"  
    02 #include <QDebug>  
    03 MThread::MThread(QObject *parent)  
    04     : QThread(parent)  
    05 {  
    06     myTimer.start(1);  
    07     connect(&myTimer, SIGNAL(timeout()), this, SLOT(slotPrint()));  
    08 }  
    09   
    10 MThread::~MThread()  
    11 {  
    12   
    13 }  
    14   
    15 void MThread::run()  
    16 {     
    17     for (int i = 0; i < 100; ++i) {  
    18         for (int j = 0 ; j < 10000; ++j) {  
    19             qDebug()<<"---------"<<i;  
    20         }  
    21     }  
    22     exec();  
    23 }  
    24   
    25 void MThread::slotPrint()  
    26 {  
    27     qDebug()<<"==============================";  
    28   
    29 }
     
     
     
    运行后出现:
     
    ... 
    ... 
    ---------9 
    ============================================================== 
    ---------9 
    ... 
    ...
    不能误以为:在一个QThread类的派生类中,run()函数中的语句在运行时,可能被本线程定时器超时slot中断. (错误)
    事实上,slotPrint()在创建MThread的实例的线程中执行,而run()函数在新的线程中运行。
     
    POINT 2:线程B中的对象要想接收线程A中的对象发来的signal, 必须进入exec(), 如在exec()前有死循环, 没有进入exec(), 则线程B中的对象不会收到signal.
     
    实例代码4:
    1 void MThread::run()  
    2 {  
    3     while(1) {  
    4         dosomething();  //此循环永不退出  
    5     }  
    6     exec();             //如果此事件循环不能进入,则此线程不会收到任何signal  
    7 }
     
     
    POINT 3:线程A中的指针可指向线程B中创建的对象实例,  这个实例属于线程B. 指针仅仅是一个地址(自己补充:存放地址的变量,而不是地址), 而对象实例的变量/代码等都属于线程B.
    实例代码5:
    01 class MThread : public QThread  
    02 {  
    03     Q_OBJECT  
    04   
    05 public:  
    06     MThread(QObject *parent = 0);  
    07     ~MThread();  
    08     void run();  
    09     MPrint *mprint;  
    10 };  
    11 void MThread::run()  
    12 {  
    13     mprint = new MPrint;  
    14     exec();  
    15 }  
    16 //如此声明,mprint所指向的对象属于另一个线程,即原始线程.
     
     
    实例代码6:
    01 class MThread : public QThread  
    02 {  
    03     Q_OBJECT  
    04   
    05 public:  
    06     MThread(QObject *parent = 0);  
    07     ~MThread();  
    08     void run();  
    09     MPrint *mprint;  
    10 private:  
    11     QTimer *myTimer;  
    12   
    13   
    14 private slots:  
    15     void slotPrint();     
    16     void testFoo();  
    17 };  
    18   
    19 void MThread::run()  
    20 {  
    21     myTimer = new QTimer;  
    22     mprint = new MPrint;  
    23     myTimer->setInterval(100);  
    24     connect(myTimer, SIGNAL(timeout()), this, SLOT(testFoo()), Qt::DirectConnection);  
    25     QTimer::singleShot(0, myTimer,SLOT(start()));  
    26     exec();  
    27 }
     
     
    以上这样写run(),myTimer在run()中new,即myTimer这个指针属于旧线程,但myTimer所指向的QTimer实例的实体在新的线程中,testFoo()会在新线程中执行.
     
     
    实例代码7:
    01 void MThread::run()  
    02 {  
    03     QTimer myTimer;  
    04     mprint = new MPrint;  
    05     myTimer.setInterval(100);  
    06     connect(&myTimer, SIGNAL(timeout()), this, SLOT(testFoo()), Qt::DirectConnection);  
    07     QTimer::singleShot(0, &myTimer,SLOT(start()));  
    08     //testFoo();  
    09     exec();  
    10 }
     
     
    以上这样写run(),myTimer在run()中声明,即myTimer属于新的线程,testFoo()也会在新线程中执行.
     
    实例代码8:
    01 class MThread : public QThread  
    02 {  
    03     Q_OBJECT  
    04   
    05 public:  
    06     MThread(QObject *parent = 0);  
    07     ~MThread();  
    08     void run();  
    09     MPrint *mprint;  
    10 private:  
    11     QTimer myTimer;  
    12   
    13   
    14 private slots:  
    15     void slotPrint();     
    16     void testFoo();  
    17 };  
    18   
    19   
    20 void MThread::run()  
    21 {  
    22     mprint = new MPrint;  
    23     myTimer.setInterval(100);  
    24     connect(&myTimer, SIGNAL(timeout()), this, SLOT(testFoo()));  
    25     QTimer::singleShot(0, &myTimer,SLOT(start()));  
    26     //testFoo();  
    27     exec();  
    28 }
     
     
    以上这样写run(),testFoo()会在创建myTimer的老线程中执行.因为可以看到,mytimer和this(即mythread),都是在同一个线程中,只是在另一个线程中(run()),做了connect操作.
    要注意的是,在线程B中启动线程A中的一个定时器,不能使用
    myTimer.start(),这样启动不了定时器.而应使用signal来触发start()这个slot.

     
    POINT 5:slot不会中断同线程中的slot.
    实例代码8:
    01 #include "mthread.h"  
    02 #include <QDebug>  
    03 MThread::MThread(QObject *parent)  
    04     : QThread(parent)  
    05 {  
    06     myTimer.start(1);  
    07     connect(&myTimer, SIGNAL(timeout()), this, SLOT(slotPrint()));  
    08 }  
    09   
    10 MThread::~MThread()  
    11 {  
    12   
    13 }  
    14   
    15 void MThread::run()  
    16 {  
    17     exec();  
    18 }  
    19   
    20 void MThread::slotPrint()  
    21 {  
    22     qDebug()<<"===========================";  
    23     for (int i = 0; i < 100; ++i) {  
    24         for (int j = 0 ; j < 10000; ++j) {  
    25             qDebug()<<"---------"<<i;  
    26         }  
    27     }  
    28 }
     
     
    slotPrint()函数运行完之后才会退出,说明slot不会中断slot,一个slot在执行完之后才会执行下一个slot.
    注意:slotPrint()在创建MThread实例的线程中执行.而不是使用thread->start()创建出的那个线程.
    实例代码8:
    01 #include "mthread.h"  
    02 #include <QDebug>  
    03 MThread::MThread(QObject *parent)  
    04     : QThread(parent)  
    05 {  
    06     myTimer.start(1);  
    07     connect(&myTimer, SIGNAL(timeout()), this, SLOT(slotPrint()));  
    08 }  
    09   
    10 MThread::~MThread()  
    11 {  
    12   
    13 }  
    14   
    15 void MThread::run()  
    16 {  
    17     testFoo();  
    18     exec();  
    19 }  
    20   
    21 void MThread::slotPrint()  
    22 {  
    23     qDebug()<<"=======================";  
    24   
    25 }  
    26   
    27 void MThread::testFoo()  
    28 {  
    29     for (int i = 0; i < 100; ++i) {  
    30         for (int j = 0 ; j < 10000; ++j) {  
    31             qDebug()<<"---------"<<i;  
    32         }  
    33     }  
    34 }
     
     
    以上代码中,slotPrint()与testFoo()会在两个不同的线程中执行.(自己注:slotPrint和MThread同一个线程中运行,而testFoo会在run()新生成的线程中运行)

    https://blog.csdn.net/msccreater/article/details/8821062

  • 相关阅读:
    HDU1163 Eddy&#39;s digital Roots【九剩余定理】
    【ThinkingInC++】8、说明,浅谈数据类型的大小
    教你如何使用U盘装系统
    图像不显示该问题的解决方案
    HTTP相关概念
    AndroidUI的组成部分GridView
    uploadify 3.2 后台动态传参数
    Oracle11g创建表空间语句
    Uncaught RangeError: Maximum call stack size exceeded解决思路
    panel,dialog,window组件越界问题汇总
  • 原文地址:https://www.cnblogs.com/findumars/p/8824713.html
Copyright © 2011-2022 走看看