之前对线程理解得不深入,所以对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=);
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();
std::cout<<"sleepSlot() weak up\n"<<std::endl;
} // network thread class // GUI class,run in main thread MyWidget::MyWidget(QWidget *parent=)
{
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在多线程中使用信号槽的示例的更多相关文章

  1. Qt5中的信号槽

    Qt4中的信号槽 Qt4中的信号槽是通过SIGNAL,SLOT两个宏,将参数转换成字符串.Qt编译前,会从源码的头文件中提取由signal和slot声明的信号和槽的函数, 将其组成一张信号和槽对应的字 ...

  2. Qt计算器开发(二):信号槽实现数学表达式合法性检查

    表达式的合法性 由于我们的计算器不是单步计算的,所以我们能够一次性输入一个长表达式.然而假设用户输入的长表达式不合法的话,那么就会引发灾难.所以有必要对于用户的输入做一个限制. 一些限制举例: 比方, ...

  3. 多线程中的信号机制--signwait()函数【转】

    本文转载自:http://blog.csdn.net/yusiguyuan/article/details/14237277 在Linux的多线程中使用信号机制,与在进程中使用信号机制有着根本的区别, ...

  4. QT中的信号槽

    只有继承了QObject类的类,才具有信号槽的能力.所以,为了使用信号槽,必须继承QObject. 凡是QObject类(不管是直接子类还是间接子类),都应该在第一行代码写上Q_OBJECT. 不管是 ...

  5. VS2008 Qt Designer 中自定义信号槽

    一.Qt Designer自定义槽函数 发现:在VS2008 +Qt4.7  中打开ui文件,所用的英文QT Designer工具,没有转到槽函数的功能,不如QtCreator自带的QtDesigne ...

  6. Qt 学习之路 :信号槽

    信号槽是 Qt 框架引以为豪的机制之一.熟练使用和理解信号槽,能够设计出解耦的非常漂亮的程序,有利于增强我们的技术设计能力. 所谓信号槽,实际就是观察者模式.当某个事件发生之后,比如,按钮检测到自己被 ...

  7. Qt源码学习之信号槽

    Qt源码版本 Qt 5.12.0 moc文件 Qt在编译之前会分析源文件,当发现包含了Q_OBJECT宏,则会生成另外一个标准的C++源文件(包含Q_OBJECT宏实现的代码,文件名为moc_+原文件 ...

  8. QT写hello world 以及信号槽机制

    QT是一个C++的库,不仅仅有GUI的库.首先写一个hello world吧.敲代码,从hello world 写起. #include<QtGui/QApplication> #incl ...

  9. QT学习记录之理解信号槽机制

    作者:朱金灿 来源:http://blog.csdn.net/clever101 QT的事件机制采用的信号槽机制.所谓信号槽机制,简而言之就是将信号和信号处理函数绑定在一起,比如一个按钮被单击是一个信 ...

随机推荐

  1. 深入浅出zookeeper之一:功能及本质

    zookeeper(下文简写为zk)大家都不陌生.但是,看到很多同学对zookeeper的理解过于程式化,有些地方甚至需要背,是大可不必的.把本质理解了,概念性和功能介绍都可以推出来的,而且架构要活学 ...

  2. 解读经典-《C#高级编程》第七版-Chapter1-.Net体系结构-Page1-6

    前言 大家好.这是开通本号的第一篇文章.从事IT行业已经20年了,从使用PowerBuilder做企业信息系统开始,做了七八年开发,然后转型Java不是很成功,从07年之后,我转做产品经理,机缘巧合, ...

  3. Qt5 在添加 Q_OBJECT 后发现编译出错的原因

    在 Qt 编写过程中,如多线程使用信号槽时,需要添加 Q_OBJECT,但是在添加之后发现编译老会出错.如下: class ThreadSxxx : public QThread { Q_OBJECT ...

  4. Gitlab仓库搭建及在linux/windows中免密使用gitlab(二)--技术流ken

    Gitlab简介 GitLab 是一个用于仓库管理系统的开源项目,使用Git作为代码管理工具,并在此基础上搭建起来的web服务. 可通过Web界面进行访问公开的或者私人项目.它拥有与Github类似的 ...

  5. 第一册:lesson thirty seven。

    原文: Making a bookcase. A:You are working hard,George. What are you doing . B:I am making a bookcase. ...

  6. 【转】ADO.Net对Oracle数据库的操作

    一 ADO.Net简介 [转自网络,收藏学习] 访问数据库的技术有许多,常见的有一下几种:开放数据库互联(ODBC). 数据访问对象(DAO).远程数据对象(RDO). ActiveX数据对象(ADO ...

  7. EF(EntityFramework)与mysql使用,错误终极解决方案

    我昨天写了好多篇跟mysql有关的错误,但是在今天我发现好像所有的问题都是一个原因引起的: 版本问题,我原先使用的是MySql.Data.Entity.EF6(版本号:6.10.5),今天我换成6.9 ...

  8. 从零开始学安全(十六)● Linux vim命令

    游标控制 h 游标向左移 j 游标向下移 k 游标向上移 l (or spacebar) 游标向右移 w 向前移动一个单词 b 向后移动一个单词 e 向前移动一个单词,且游标指向单词的末尾 ( 移到当 ...

  9. 【CSS】小妙招,各种问题总结方法处理

    1.实现div文字溢出自动省略号截取   overflow:hidden;  /*超过部分不显示*/   text-overflow:ellipsis;  /*超过部分用点点表示*/   white- ...

  10. python之strip()小记

    描述 Python strip() 方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列. 注意:该方法只能删除开头或是结尾的字符,不能删除中间部分的字符. 语法 strip()方法语法: ...