Qt在多线程中使用信号槽的示例

Posted 蓝域小兵

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Qt在多线程中使用信号槽的示例相关的知识,希望对你有一定的参考价值。

  之前对线程理解得不深入,所以对Qt的线程机制没有搞清楚,今天写一篇文章总结一下,如有错误,欢迎指出。

 

       首先需要理解线程是什么,线程在代码中的表现其实就是一个函数,只不过这个函数和主线程的函数同时运行,写C语言的都知道,一般代码是从main()函数开始运行的,每个线程都有一个入口函数,main()函数可以看做是主线程的入口函数,从main函数开始执行,主线程就开始了,写过一点代码的都知道,程序是从main()函数开始一条一条地往下执行的,但是有的时候我们需要同时执行A,B两个函数。初学代码时,都是先调用A函数,再调用B函数,这时是A函数执行完毕后再执行B函数,没有达到我们想要同时执行的目的。这时如果把A函数放入另一个线程中执行,那么不需要等到A函数执行完毕,B函数就可以开始执行。C++11中已经有了多线程库,简单示例如下

std::thread t(A);
B();

       你可以随便写两个函数,函数名为A,B。函数内容可以写成输出10000次A(B函数可以输出10000次B,输出次数少了可能会观察不到),你可能会发现A和B会交替出现,这就是A和B在同时执行的证明。多线程在图形界面程序中几乎是必须的,图形界面程序的主线程一般是界面线程,用于响应用户的操作,后台线程用于执行计算,通信等操作,如果不使用多线程,图形界面会因为等待计算数据(当然我说的是大量数据,少量数据你可能会感受不到)而卡住不响应用户的操作。讲到这里你也许对线程有了一个基本的印象。

 

Qt使用QThread类有两种方式,这个网上可以找到很多资料。

第一种:继承QThread类,自己写一个类(假设为MyThread),重写QThread的run()函数,新线程就会运行run()里面的代码,但是要注意的是只有run()函数里面的代码在新线程里运行,所以你自己的MyThread类里面的槽函数虽然和主线程的信号绑定了,但是只要没有放在run()里面运行,还是运行在主线程中的。

第二种:使用moveToThread(),我下面的示例代码就是使用的moveToThread()方法。QThrad中默认的run()函数启用了事件循环(exec()),所以你移动到线程中的那个对象的所有槽函数均在新线程中执行,不会阻塞主线程。看完示例就明白了。新建一个QApplication工程,把mainwindow.h改成下面的代码

// mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H #include <QApplication> #include <QObject> #include <QEvent> #include <thread> #include <iostream> #include <QThread> #include <QPushButton> #include <QVBoxLayout> #include <QMainWindow> // network thread class NetworkThread:public QObject { Q_OBJECT public: NetworkThread() { // do some initial works; } signals: void datacoming(int a); private: void memberFun(); public slots: void testSlot(); void sleepSlot(); }; // network thread class // GUI class,run in main thread class MyWidget:public QMainWindow { Q_OBJECT public: QPushButton *firstButton,*secondButton,*thirdButton; QVBoxLayout *layout; QWidget *p; public: explicit MyWidget(QWidget *parent); ~MyWidget(); signals: void signalTestStart(int a=0); void startNetworkSleep(); public slots: void secondButtonClicked(); }; // GUI class // csApplication class class csApplication:public QApplication { Q_OBJECT public: csApplication(int argc,char *argv[]); MyWidget *mywindow; NetworkThread *netthd; QThread *t; ~csApplication(); }; // csApplication class #endif // MAINWINDOW_H

把main.cpp改成下面的代码,并删去mainwindow.cpp

// main.cpp

#include "mainwindow.h"



// network thread

void NetworkThread::testSlot()
{
    std::cout<<"\nin testSlot()\n thread id:"<<std::this_thread::get_id()<<std::endl;
    memberFun();
}

void NetworkThread::memberFun()
{
    std::cout<<"\nin NetworkThread::memberFun()\nthread id:"<<std::this_thread::get_id()<<"\n"<<std::endl;
}

void NetworkThread::sleepSlot()
{
    std::cout<<"in NetworkThread::sleepSlot()\n thread id:"<<std::this_thread::get_id()<<"\nthen sleep 5 seconds\n";
    QThread::sleep(5);
    std::cout<<"sleepSlot() weak up\n"<<std::endl;
}

// network thread class

// GUI class,run in main thread

MyWidget::MyWidget(QWidget *parent=0)
{
    firstButton = new QPushButton(tr("first"));
    secondButton = new QPushButton(tr("second"));
    thirdButton = new QPushButton(tr("third"));

    layout = new QVBoxLayout;
    layout->addWidget(firstButton);
    layout->addWidget(secondButton);
    layout->addWidget(thirdButton);

    p=new QWidget;

    p->setLayout(layout);

    setCentralWidget(p);

}
MyWidget::~MyWidget()
{
    delete firstButton;
    delete secondButton;
    delete thirdButton;
    delete p;
    delete layout;
}

void MyWidget::secondButtonClicked()
{
    emit startNetworkSleep();
    std::cout<<"in MyWidget::secondButtonClicked()\n thread id: "<<std::this_thread::get_id()<<"\n"<<std::endl;
}

// GUI class

// csApplication class

csApplication::csApplication(int argc, char *argv[]):QApplication(argc,argv)
{

    std::cout<<"\nin csApplication()\nthread id:"<<std::this_thread::get_id()<<"\n"<<std::endl;
    mywindow = new MyWidget();
    netthd = new NetworkThread();
    t = new QThread();

    connect(mywindow->firstButton,SIGNAL(clicked()),netthd,SLOT(testSlot()),Qt::QueuedConnection);
    connect(mywindow->secondButton,SIGNAL(clicked()),mywindow,SLOT(secondButtonClicked()));
    connect(mywindow,SIGNAL(startNetworkSleep()),netthd,SLOT(sleepSlot()),Qt::QueuedConnection);

    netthd->moveToThread(t);
    t->start();
    mywindow->show();

}
csApplication::~csApplication()
{
    delete mywindow;
    delete netthd;
    delete t;
}

// csApplication class


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

    return a.exec();
}

点击运行就可以了。

 

以上是关于Qt在多线程中使用信号槽的示例的主要内容,如果未能解决你的问题,请参考以下文章

QT多线程里定义信号与发射信号

Qt::ConnectionType(信号与槽的传递方式)

Qt::浅谈信号槽连接,参数在多线程中的使用

Qt信号和槽的问题

Qt的信号槽机制可以保障线程安全吗

初见QT---信号和槽