理解Qt多线程类

来源:互联网 发布:智库研究员 知乎 编辑:程序博客网 时间:2024/04/28 10:40
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.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:

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.};
11.void MThread::run()
12.{
13.    mprint = new MPrint;
14.    exec();
15.}
16.//如此声明,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.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:

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.5.public:
6.    MThread(QObject *parent = 0);
7.    ~MThread();
8.    void run();
9.    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:

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.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.}
29.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.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.}
35.以上代码中,slotPrint()与testFoo()会在两个不同的线程中执行.


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/mmmcu2004/archive/2008/12/07/3466778.aspx

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 2岁宝宝不吃蔬菜怎么办 事情想多了头疼怎么办 生气引起的肝疼怎么办 饿又懒得买吃的怎么办 四岁宝宝缺铁怎么办 宝宝吃母乳缺铁怎么办 九个月宝宝缺铁怎么办 2岁宝宝走路不稳怎么办 两岁宝宝爱打人怎么办 2岁宝宝脾气暴躁怎么办 二岁宝宝有口气怎么办 bl良品数码欺骗怎么办 喝酒喝的胃疼怎么办 喝酒喝多了胃疼怎么办 喝白酒喝的难受怎么办 吃饭后恶心想吐怎么办 喝奶茶恶心想吐怎么办 怀孕了一直想吐怎么办 肝不好一直想吐怎么办 胃老是恶心想吐怎么办 胃疼拉肚子拉水怎么办 半夜胃疼呕吐怎么办啊, 孕妇胃疼怎么办5个月 孕早期饿的胃疼怎么办 怀孕7个月胃痛怎么办 怀孕了胃疼的厉害怎么办 孕晚期老是胃疼怎么办 孕晚期半夜胃疼怎么办 吃多了反胃想吐怎么办 抽烟胃恶心想吐怎么办 孕妇7个月头疼怎么办 我的世界狗死了怎么办 户户通搜不到台怎么办 两车相撞我全责怎么办 我全责自己的车怎么办 没有我你怎么办 酷我 仿古砖上的水泥怎么办 异界气息的ss怎么办 前夫威胁我我该怎么办 怀孕了不确定孩子是谁的怎么办 怀孕了不是老公的怎么办