第79课 - 多线程中的信号与槽(中)

版权声明:课程笔记内容整理于狄泰软件 https://blog.csdn.net/qq_39654127/article/details/81983537

1、令人不解的问题 

当槽函数是线程类中的成员时,为什么依

然不在本线程内被调用执行? 

 

隐藏的问题 

      -对象依附于哪一个线程? 

      -对象的依附性与槽函数执行的关系? 

      -对象的依附性是否可以改变? 

对象依附于哪一个线程? 

          默认情况下,对象依附于自身被创建的线程;例 如:

          对象在主线程(main()函数)中被创建,则依附于主线程。 

int main(int argc, char *argv[])
{
    //...

    TestThread t; //依附于主线程
    MyObject m; //依附于主线程

    //...
}

对象的依附性与槽函数执行的关系? 

             默认情况下,槽函数在其所依附的线程中被调用执行! 

int main(int argc, char *argv[])
{
    //...

    TestThread t; //依附于主线程
    MyObject m; //依附于主线程

    /*下面连接的槽函数都在主线程中被调用执行*/
    QObject::connect(&t, SIGNAL(started()), &m, SLOT(getStarted()));
    QObject::connect(&t, SIGNAL(testSignal()), &m, SLOT(testSlot()));

    //...
}

 

对象的依附性是否可以改变? 

           QObject:: moveToThread用于改变对象的线

           程依附性,使得对象的槽函数在依附的线程中

           被调用执行。

int main(int argc, char *argv[])
{
    //...

    TestThread t; //依附于主线程
    MyObject m; //依附于主线程

    /*改变m的线程依附性,使其依附于线程t*/
    m.moveToThread(&t);
    
    //...
}

2、编程实验 

对象的依附性 79-1.pro 

TestThread.h

#ifndef TESTTHREAD_H
#define TESTTHREAD_H

#include <QThread>

class TestThread : public QThread
{
    Q_OBJECT

protected:
    void run();
public:
    explicit TestThread(QObject *parent = 0);
    
signals:
    void testSignal();
protected slots:
    void testSlot();
};

#endif // TESTTHREAD_H

TestThread.cpp

#include "TestThread.h"
#include <QDebug>

TestThread::TestThread(QObject *parent) :
    QThread(parent)
{
    connect(this, SIGNAL(testSignal()), this, SLOT(testSlot()));
}

void TestThread::run()
{
    qDebug() << "void TestThread::run() -- begin tid = " << currentThreadId();

    for(int i=0; i<5; i++)
    {
        qDebug() << "void TestThread::run() i = " << i;

        sleep(1);
    }

    emit testSignal();

    qDebug() << "void TestThread::run() -- end";
}

void TestThread::testSlot()
{
    qDebug() << "void TestThread::testSlot() tid = " << currentThreadId();
}

MyObject.h

#ifndef MYOBJECT_H
#define MYOBJECT_H

#include <QObject>

class MyObject : public QObject
{
    Q_OBJECT
public:
    explicit MyObject(QObject *parent = 0);
    
signals:
    
protected slots:
    void getStarted();
    void testSlot();
};

#endif // MYOBJECT_H

MyObject.cpp

#include "MyObject.h"
#include <QThread>
#include <QDebug>

MyObject::MyObject(QObject *parent) :
    QObject(parent)
{
}

void MyObject::getStarted()
{
    qDebug() << "void MyObject::getStarted() tid = " << QThread::currentThreadId();
}

void MyObject::testSlot()
{
    qDebug() << "void MyObject::testSlot() tid = " << QThread::currentThreadId();
}

main.cpp

#include <QtCore/QCoreApplication>
#include <QDebug>
#include <QThread>
#include "TestThread.h"
#include "MyObject.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    qDebug() << "main() tid = " << QThread::currentThreadId();

    TestThread t;
    MyObject m;

    QObject::connect(&t, SIGNAL(started()), &m, SLOT(getStarted()));
    QObject::connect(&t, SIGNAL(testSignal()), &m, SLOT(testSlot()));

    m.moveToThread(&t);

    t.start();

    return a.exec();
}

线程中的事件循环 

     -信号与槽的机制需要事件循环的支持

     -QThread类中提供的exec()函数用于开启线程的事件循环

     -只有事件循环开启,槽函数才能在信号发送后被调用 

                   主线程开启了事件循环,所以槽函数能在主线程被调用

                    t 线程没有开启事件循环,所以槽函数不能在t线程调用 

                                        即要槽函数在指定的线程中调用,就需要在

                                        指定的线程中调用exec()开启事件循环

小结论 

       -前提条件 

                对象依附的线程需要开启了事件循环

       -后置结果 

                对象中的槽函数在依附的线程中被调用执行 

3、编程实验 

线程的事件循环   79-1.pro 

在TestThread中开启t的事件循环

void TestThread::run()
{
    qDebug() << "void TestThread::run() -- begin tid = " << currentThreadId();

    for(int i=0; i<5; i++)
    {
        qDebug() << "void TestThread::run() i = " << i;

        sleep(1);
    }

    emit testSignal();

    exec(); //开启线程t的事件循环

    qDebug() << "void TestThread::run() -- end";
}

那如果让t的槽函数也在自己的线程中被调用

只需在main函数中加入t.moveToThread(&t);

 

研究槽函数的具体执行线程有什么意义? 

            当信号的发送与对应槽函数的执行在不同线程中 

            时可能产生临界资源的竞争问题! 

                     例如:示例中的线程类中某个成员变量在本线程中改变,

                     但他的槽函数却在其它线程同时调用,同时修改这一变量

4、小结 

默认情况下,对象依附于自身被创建的线程 

QObject::moveToThread用于改变对象的线程依附性 

信号与槽的机制需要事件循环的支持 

exec()函数用于开启线程的事件循环 

对象中的槽函数在依附的线程中被调用执行 

 

5、To be continued

为什么exec后面的内容没有被执行?

猜你喜欢

转载自blog.csdn.net/qq_39654127/article/details/81983537
今日推荐