Qt文档阅读笔记-Qt工作笔记-QThread解析与实例(主线程发送信号给子线程)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq78442761/article/details/82732980

目录

QThread

官方解析

博主栗子

子线程发射信号给主线程


QThread

官方解析

Detailed Description

QThread类提供了跨平台的线程管理的API。
QThread对象在程序中管理一个线程。 使用run()来执行,默认情况下run()通过调用exec()实现事件循环,并且run()使得QThread的对象的线程中Qt的事件循环跑起来。
可以用QObject::moveToThread()使worker对象放入线程中。

  class Worker : public QObject
  {
      Q_OBJECT

  public slots:
      void doWork(const QString &parameter) {
          QString result;
          /* ... here is the expensive or blocking operation ... */
          emit resultReady(result);
      }

  signals:
      void resultReady(const QString &result);
  };

  class Controller : public QObject
  {
      Q_OBJECT
      QThread workerThread;
  public:
      Controller() {
          Worker *worker = new Worker;
          worker->moveToThread(&workerThread);
          connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
          connect(this, &Controller::operate, worker, &Worker::doWork);
          connect(worker, &Worker::resultReady, this, &Controller::handleResults);
          workerThread.start();
      }
      ~Controller() {
          workerThread.quit();
          workerThread.wait();
      }
  public slots:
      void handleResults(const QString &);
  signals:
      void operate(const QString &);
  };


在这个代码里面Worker的槽函数在另外一个线程中执行。但可以使用信号与槽让任意的object对象(继承了QObject,并且带有Q_OBJECT宏)信号连接Worker的槽函数。这种跨线程的信号与槽的连接方式是安全的,这得归功于connect()函数的第五个参数(参考链接)默认调用了queued connections。
另外一种方式让代码运行在其他线程的方式是,子类化QThread类,并且重新实现run()函数,栗子如下:

  class WorkerThread : public QThread
  {
      Q_OBJECT
      void run() Q_DECL_OVERRIDE {
          QString result;
          /* ... here is the expensive or blocking operation ... */
          emit resultReady(result);
      }
  signals:
      void resultReady(const QString &s);
  };

  void MyObject::startWorkInAThread()
  {
      WorkerThread *workerThread = new WorkerThread(this);
      connect(workerThread, &WorkerThread::resultReady, this, &MyObject::handleResults);
      connect(workerThread, &WorkerThread::finished, workerThread, &QObject::deleteLater);
      workerThread->start();
  }


在这个栗子中,thread将会在函数返回的时候退出。他们将不会在线程中运算事件循环,除非他们调用exec().
要注意QThread实例存在与谁实例化他的线程中,而不是在谁调用了run()这个函数的线程中。这就意味着QThread以队列连接的信号与槽,将会执行在实例化他的线程中,而不是调用run()函数这个线程中。因此如果希望在新线程里面调用槽函数得使用worker对象显示出的方式;不应该将槽函数直接实例在子类化的QThread中。
当子类化QThread类后,构造函数会旧的(实例化他的)那个线程中执行,而run()的执行将会在新线程中。如果这两个函数都访问了成员变量,从两个不同的线程中访问这个变量,要检测这么做是否安全!

Note:要小心,在不同对象或者线程中交互。查看Synchronizing Threads查看详情!

博主栗子

子线程发射信号给主线程

当子线程里面emit一个signal给主线程,这是十分常见的,但主线程emit一个signal给子线程那么会发送些什么呢!

运行截图如下:

源码瑞星啊:

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

class QThread;
class Worker;

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = 0);
    ~Widget();

protected:
    void timerEvent(QTimerEvent *event)Q_DECL_OVERRIDE;


signals:
    void hello();
    void sendMsg();

private:
    QThread *thread[3];
    Worker *worker[3];
};

#endif // WIDGET_H

worker.h

#ifndef WORKER_H
#define WORKER_H

#include <QObject>

class Worker : public QObject
{
    Q_OBJECT
public:
   Worker(QObject *parent = 0);

public slots:
    void beginToWork();
    void mainThreadMsg();
};

#endif // WORKER_H

main.cpp

#include "widget.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();

    return a.exec();
}

widget.cpp

#include "widget.h"
#include "worker.h"
#include <QDebug>
#include <QThread>
Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    for(int i=0;i<3;i++){
        thread[i]=new QThread;
        worker[i]=new Worker;
        worker[i]->moveToThread(thread[i]);
        connect(thread[i],&QThread::finished,worker[i],&QObject::deleteLater);
        connect(this,&Widget::hello,worker[i],&Worker::beginToWork);
        connect(this,SIGNAL(sendMsg()),worker[i],SLOT(mainThreadMsg()));
        thread[i]->start();
    }

    emit hello();
    startTimer(1000);


}

Widget::~Widget()
{
    for(int i=0;i<3;i++){
        thread[i]->quit();
        thread[i]->wait();
        delete thread[i];
        delete worker[i];
    }
}

void Widget::timerEvent(QTimerEvent *event)
{
    Q_UNUSED(event)
    emit sendMsg();

//    for(int i=0;i<3;i++){
//        qDebug()<<"main thread, worker "<<i;
//        worker[i]->mainThreadMsg();
//    }
}

worker.cpp

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

Worker::Worker(QObject *parent) : QObject(parent)
{

}

void Worker::beginToWork()
{
    while(true){
        QThread::sleep(2);
        qDebug()<<QThread::currentThreadId()<<" beginToWork";
        mainThreadMsg();
    }
}

void Worker::mainThreadMsg()
{
    qDebug()<<"mainThreadMsg called!"<<QThread::currentThreadId();
}

猜你喜欢

转载自blog.csdn.net/qq78442761/article/details/82732980