打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
<ZT>理解Qt多线程类 - yanboo's blog - 歪酷
userphoto

2010.09.03

关注

<ZT>理解Qt多线程类

yanboo 发表于 2010-03-04 16:16:10

转帖http://blog.csdn.net/manio/archive/2008/08/19/2794171.aspx

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

例1:

class MThread :public QThread
{
public:
    MThread();
    ~MThread();
    void run();
    void foo();
    ...
   
};
class MDialog :public QDialog
{
    ...
    MThread *mythread;
};
MDialog::MDialog()
{
    mythread = new MThread;
    ...
}
需要注意的是,在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:

#include "mthread.h"
#include <QDebug>
MThread::MThread(QObject *parent)
    : QThread(parent)
{
    myTimer.start(1);
    connect(&myTimer, SIGNAL(timeout()), this, SLOT(slotPrint()));
}
MThread::~MThread()
{
}
void MThread::run()
{  
    for (int i = 0; i < 100; ++i) {
        for (int j = 0 ; j < 10000; ++j) {
            qDebug()<<"---------"<<i;
        }
    }
    exec();
}
void MThread::slotPrint()
{
    qDebug()<<"==============================";
}
运行后出现:

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

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

 

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

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

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

例1:

class MThread : public QThread
{
    Q_OBJECT
public:
    MThread(QObject *parent = 0);
    ~MThread();
    void run();
    MPrint *mprint;
};
void MThread::run()
{
    mprint = new MPrint;
    exec();
}
//如此声明,mprint所指向的对象属于另一个线程.
例2:

class MThread : public QThread
{
    Q_OBJECT
public:
    MThread(QObject *parent = 0);
    ~MThread();
    void run();
    MPrint *mprint;
private:
    QTimer *myTimer;
private slots:
    void slotPrint();  
    void testFoo();
};
void MThread::run()
{
    myTimer = new QTimer;
    mprint = new MPrint;
    myTimer->setInterval(100);
    connect(myTimer, SIGNAL(timeout()), this, SLOT(testFoo()), Qt::DirectConnection);
    QTimer::singleShot(0, myTimer,SLOT(start()));
    exec();
}
以上这样写run(),myTimer在run()中new,即myTimer这个指针属于旧线程,但myTimer所指向的QTimer实例的实体在新的线程中,testFoo()会在新线程中执行.

例3:

void MThread::run()
{
    QTimer myTimer;
    mprint = new MPrint;
    myTimer.setInterval(100);
    connect(&myTimer, SIGNAL(timeout()), this, SLOT(testFoo()), Qt::DirectConnection);
    QTimer::singleShot(0, &myTimer,SLOT(start()));
    //testFoo();
    exec();
}
以上这样写run(),myTimer在run()中声明,即myTimer属于新的线程,testFoo()也会在新线程中执行.

例4:

class MThread : public QThread
{
    Q_OBJECT
public:
    MThread(QObject *parent = 0);
    ~MThread();
    void run();
    MPrint *mprint;
private:
    QTimer myTimer;
private slots:
    void slotPrint();  
    void testFoo();
};
void MThread::run()
{
    mprint = new MPrint;
    myTimer.setInterval(100);
    connect(&myTimer, SIGNAL(timeout()), this, SLOT(testFoo()));
    QTimer::singleShot(0, &myTimer,SLOT(start()));
    //testFoo();
    exec();
}
以上这样写run(),testFoo()会在创建myTimer的老线程中执行.因为可以看到,mytimer和this(即mythread),都是在同一个线程中,只是在另一个线程中(run()),做了connect操作.

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

 

POINT 5:
slot不会中断同线程中的slot.

例1:

#include "mthread.h"
#include <QDebug>
MThread::MThread(QObject *parent)
    : QThread(parent)
{
    myTimer.start(1);
    connect(&myTimer, SIGNAL(timeout()), this, SLOT(slotPrint()));
}
MThread::~MThread()
{
}
void MThread::run()
{
    exec();
}
void MThread::slotPrint()
{
    qDebug()<<"===========================";
    for (int i = 0; i < 100; ++i) {
        for (int j = 0 ; j < 10000; ++j) {
            qDebug()<<"---------"<<i;
        }
    }
}
slotPrint()函数运行完之后才会退出,说明slot不会中断slot,一个slot在执行完之后才会执行下一个slot.

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

例2:

#include "mthread.h"
#include <QDebug>
MThread::MThread(QObject *parent)
    : QThread(parent)
{
    myTimer.start(1);
    connect(&myTimer, SIGNAL(timeout()), this, SLOT(slotPrint()));
}
MThread::~MThread()
{
}
void MThread::run()
{
    testFoo();
    exec();
}
void MThread::slotPrint()
{
    qDebug()<<"=======================";
}
void MThread::testFoo()
{
    for (int i = 0; i < 100; ++i) {
        for (int j = 0 ; j < 10000; ++j) {
            qDebug()<<"---------"<<i;
        }
    }
}
以上代码中,slotPrint()与testFoo()会在两个不同的线程中执行.

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
IOS 线程处理 子线程的启动与结束
QT 线程暂停,继续执行的一种实现
Linux下Qt多线程编程
关于QT的movetothread用法
QT笔记之 GUI(主)线程与子线程之间的通信
Android Framework中的线程Thread及它的threadLoop方法
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服