Qt多线程学习-用例子来理解多线程

 

01 class MThread :public QThread  

02 {  

03 public:  

04     MThread();  

05     ~MThread();  

06     void run();  

07     void foo();  

08     ...  

09        

10 };
 


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

例1:

显示代码打印
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中,使用

 

1.mythread->foo();
foo()是在线程A中执行的.

 

在MDialog中使用

 

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

 

例2:

 

 

显示代码打印
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 }
 

 

 

运行后出现:

 

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:

显示代码打印
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所指向的对象属于另一个线程.
 

 

例2:

显示代码打印
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()会在新线程中执行.

例3:

显示代码打印
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()也会在新线程中执行.

例4:

显示代码打印
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.

例1:

显示代码打印
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()创建出的那个线程.

例2:

显示代码打印
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()会在两个不同的线程中执行.


文章出处:飞诺网(www.diybl.com):http://www.diybl.com/course/3_program/c/c_js/20090303/157373.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值