QT 多线程信号与槽(一)

QT 中 QObject 作QT中类的最终父类,具有自定义信号与槽的能力,只要继承自这个类的类,也一样拥有自定义信号和槽的能力。QT 中定义信号与槽是十分有用的,那我们的线程类是不是也有这个能力呢?

查一下 QThread 的源码,我们发现 QThread 是继承自 QObject 的,他确实有自定义信号和槽的能力 !!!

class Q_CORE_EXPORT QThread : public QObject
{
	。。。
};

那他有没有已经定义好的方便我们使用的信号呢?看一下源码就知道啦。

Q_SIGNALS:
    void started(QPrivateSignal);
    void finished(QPrivateSignal);

我们来看看 QThread 是不是真的支持这两个信号。

#include 
#include 
#include 
#include 

class ThreadTest : public QThread
{
public:
    ThreadTest() {}

    void run()
    {
        msleep(2000);
    }
};


class MyClass : public QObject
{
    Q_OBJECT
public:
    explicit MyClass(QObject *parent = nullptr){}

public slots:
    void getstarted()
    {
        qDebug()<<objectName()<<":"<<"getstarted()";
    }
    void getfinished()
    {
        qDebug()<<objectName()<<":"<<"getfinished()";
    }
};

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

    ThreadTest threada;
    MyClass my;

    my.setObjectName("my");

    QObject::connect(&threada,SIGNAL(started()),&my,SLOT(getstarted()));
    QObject::connect(&threada,SIGNAL(finished()),&my,SLOT(getfinished()));

    threada.start();

    return a.exec();
}

从运行结果上看确实收到了这两个信号呢。
在这里插入图片描述
在工程开发中,我们可以利用这两个信号来知道线程是什么时候开启和结束的。


QThread 已经定好了一些供我们使用的方便的信号,现在我们来试一试自定义信号和槽。

我们在刚才的代码上稍加修改

class MyClass : public QObject
{
    Q_OBJECT
public:
    explicit MyClass(QObject *parent = nullptr){}

public slots:
    void getstarted()
    {
        qDebug()<<objectName()<<":"<<"getstarted()";
    }

    void getfinished()
    {
        qDebug()<<objectName()<<":"<<"getfinished()";
    }
signals:
};


class ThreadTest : public QThread
{
    Q_OBJECT
public:
    ThreadTest()
    {
        connect(this,SIGNAL(counter(int)),this,SLOT(getCounter(int)));
        connect(this,SIGNAL(counter_reset()),this,SLOT(on_counter_reset()));
    }

    void run()
    {

        int m_counter = 0;
        for(int i = 0;i<10;i++)
        {
            if(0==i%5)
            {
                m_counter = 0;
                emit counter_reset();
            }

            emit counter(m_counter);
            m_counter = m_counter + 1;
            msleep(200);
        }
    }
signals:
    void counter(int n);
    void counter_reset();

public slots:
    void getCounter(int n)
    {
        qDebug()<< "getCounter : "<<n;
    }
    void on_counter_reset()
    {
        qDebug()<< "counter reset now !";
    }
};

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

    ThreadTest threada;
    MyClass my;

    my.setObjectName("my");

    QObject::connect(&threada,SIGNAL(started()),&my,SLOT(getstarted()));
    QObject::connect(&threada,SIGNAL(finished()),&my,SLOT(getfinished()));

    threada.start();

    return a.exec();
}

运行结果
QT 多线程信号与槽(一)_第1张图片


我们应该要知道

  • 进程中存在栈空间的概念
  • 这个栈空间是专门用于函数调用的(比如保存函数参数,局部变量等)
  • 线程拥有独立的栈空间(可以利用这个栈空间调用其他函数)

如果一个函数的函数体中没有访问临界资源的代码,那么这个函数可以被多个线程同时调用,不会产生任何副作用。因为线程调用函数的时候用的是自己的栈空间,既然线程的栈空间是独立的,那么谁调用函数就用谁的栈空间,互不干扰。

所以问题来了,槽函数本质也是个函数,那么槽函数是谁调用的啊???是主线程还是定义槽函数的线程还是其他线程???

一般来说,我们开启一个线程,那么这个线程应该会有自己的线程 id。为了知道当前线程的 id ,我们先看看QThread有没有提供方便我们使用的方法。

从 QThread 的类定义中我们可以找到这个玩意

static Qt::HANDLE currentThreadId() Q_DECL_NOTHROW Q_DECL_PURE_FUNCTION;

那我们就试一试呗,看看是哪个线程调用槽函数。

#include 
#include 
#include 
#include 

class MyClass : public QObject
{
    Q_OBJECT
public:
    explicit MyClass(QObject *parent = nullptr){}

public slots:
    void getstarted()
    {
        qDebug()<<objectName()<<":"<<"getstarted() , tid :"<<QThread::currentThreadId();
    }

    void getfinished()
    {
        qDebug()<<objectName()<<":"<<"getfinished(), tid :"<<QThread::currentThreadId();
    }

signals:
};

class ThreadTest : public QThread
{
    Q_OBJECT
public:
    ThreadTest()
    {
        connect(this,SIGNAL(counter(int)),this,SLOT(getCounter(int)));
        connect(this,SIGNAL(counter_reset()),this,SLOT(on_counter_reset()));
    }

    void run()
    {
        qDebug()<<"ThreadTest tid"<<currentThreadId();
        int m_counter = 0;
        for(int i = 0;i<10;i++)
        {
            if(0==i%5)
            {
                m_counter = 0;
                emit counter_reset();
            }

            emit counter(m_counter);
            m_counter = m_counter + 1;
            msleep(200);
        }
    }
signals:
    void counter(int n);
    void counter_reset();

public slots:
    void getCounter(int n)
    {
        qDebug()<< "tid:"<<currentThreadId()<< " , getCounter : "<<n;
    }
    void on_counter_reset()
    {
        qDebug()<< "tid:"<<currentThreadId()<< "counter reset now !";
    }
};

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

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

    ThreadTest threada;
    MyClass my;

    my.setObjectName("my");

    QObject::connect(&threada,SIGNAL(started()),&my,SLOT(getstarted()));
    QObject::connect(&threada,SIGNAL(finished()),&my,SLOT(getfinished()));

    threada.start();

    return a.exec();
}

运行结果
QT 多线程信号与槽(一)_第2张图片
从运行结果看,我们的槽函数好像并不是在我们开启的线程中调用的呢,而是在主线程中。

可是我们槽函数在线程类中写的,却跑到主线程中调用了,大家不觉得奇怪吗。这样难道不会出现什么奇怪的 bug 吗?是 QT 不完善?还是别的原因?


QT 多线程信号与槽(二)

你可能感兴趣的:(QT)