qt多线程网络编程(qt 多线程)
QT 网络编程问题
先做一个QTcpServer作为监听socket,监听后如果出发newConnection信号,说明有连接进来。
然后通过nextPendingConnection()可以得到一个QTcpSocket,这就是用来和客户端进行通信用的套接字。
监听socket仍然可以继续监听。QTcpSocket可以用来和客户端通信。
如果通信负荷比较大,可以把每个客户端socket放入单独的线程(或进程)进行处理。负荷不大,则不需要。
qt多线程调用函数问题
主界面有两个按钮,点击“开始”按钮,触发一个信号,然后子线程打印一条信息,点击“结束”按钮,关闭线程
线程相关类定义如下
线程类变量定义如下
线程启动、信号槽及实现如下。在构造函数中通过thread.start()启动线程。
运行程序,并查看程序输出。点击一下“开始”按钮,会触发线程打印一条日志,再点击一下“开始”按钮,线程再次打印一条日志。点击“结束”按钮,打印线程结束。这时再点击“开始”按钮,线程将不再打印日志
修改线程打印函数为一个for循环,并在每次循环后sleep(5)秒
运行程序,然后点击“开始”按钮,线程开始打印日志。打印一两条后点击“结束”按钮,程序并没有停止打印日志,而是等到for循环结束后,才打印线程结束的日志。这说明线程并没有结束
修改线程结束函数如下,使用terminal函数。再次执行相同的步骤。
线程可以正常退出,但是程序关闭时崩溃。
修改线程打印函数,增加flag标识,在线程退出时,修改该flag标识,达到for循环退出的效果。这样线程可以正常退出,而且程序关闭时也不会崩溃
qt中如何实现多线程?
QT线程是独立的类:
在QT中添加C++类,头文件引用#include QThread;类公开,这样写:
class XXXX:public QThread,类里面申明Q_OBJECT,直接写在里面。signals: XXX();这是你的订阅事件名。private:void run();这是run函数;public: int cona=3;这是变量,一定要public。
cpp文件里引用头文件,run函数里面写方法:
void XXXX::run()
{
do
{
msleep(cona);
emit connec();
}while(true);
}
上面就是线程类了。现在我们在窗体中应用,先在头文件申明
头文件private: XXXX *thread1;XXXX *thread2;
构造函数中初始化他们
thread1=new XXXX();
thread1-cona=3;
QObject::connect(thread1,SIGNAL(connec()),this,SLOT(XXX信号1()));
thread2=new XXXX();
thread2-cona=4;
QObject::connect(thread2,SIGNAL(connec()),this,SLOT(XXX信号2()));
XXX信号1()是读A数据,XXX信号2()读B数据。
按钮1的信号槽里写方法同时进行每3秒读A、没4秒读B
thread1-start();
thread2-start();
要结束谁就用 xxxx-terminate();
看明白没?QT可不同与C++,你不熟悉编程环境,是很难理解的。
Qt如何进行创建多线程
在Qt中使用多线程,目前就我使用过的有两种,一是子类化QThread,重写run函数,在run函数里实现自己的代码,这一部分代码通常是比较耗时,或者干脆直接阻塞的。比如一个while循环,设置一个标志,判断循环结束。
这样的例子在网上有很多,就不写了。
这样写的话,会有一些东西需要了解。
子类化QThread的方法,只有run函数里面的内容是执行在子线程里的,其他的部分,比如槽函数什么的还是在主线程里执行(假设是在主线程开启的该子线程)。
还有一种方法,是子类化QObject,新建一个线程,然后使用MoveToThread把这个类的对象移到新建的线程中,这种做法使得它所有的槽函数都是执行在新开辟的线程里面。
如果直接(QObject对象).abc()的话,这个成员函数是在主进程内执行,可能会出现"QObject::killTimer: timers
cannot be stopped from another thread"的运行错误。
使用第二种方法的话,貌似会遇到这样的问题:如果在一个槽函数中把子线程阻塞,其他的槽函数无法接受来自主线程
Qt多线程里为什么我创建了多个线程,可每个线程的执行效率很低
多线程也是有代价的,在CPU和操作系统 上有明确的要求,否则反而达不到多线程的优势。
QT中的信号与事件,多线程
当某个事件发生之后,比如,按钮检测到自己被点击了一下,它就会发出一个信号(signal)。这种发出是没有目的的,类似广播。如果有对象对这个信号感兴趣,它就会使用连接(connect)函数,将想要处理的信号和自己的一个函数(槽函数(slot))绑定并处理这个信号。
Qt信号槽-原理分析
信号与槽的连接方式
事件发生时,qt创建了一个代表它的对象,
一般的事件传递方式是调用virtual函数。可以把自己想做的处理写在当前函数,然后把其他的都传递给base类处理。
更通用的处理方式:
可以在事件处理之前先通过filter,阻止特定的event传递给target widget,通过installEventFilter和removeEventFilter控制。
用户可以自定义自己的事件,并生成一个实例,通过sendEvent()和postEvent()发送它们。
两种方式
原型:void QObject::moveToThread( QThread * targetThread )
改变该对象与线程之间执行的关系,并不改变谁拥有该对象,只是让该对象执行成员函数时利用了target thread。「在哪创建就属于哪」这句话放在任何地方都是适用的。
多线程
一、什么是Qt消息循环
Qt消息循环,就是从一个队列中不断取出消息,并响应消息的过程。窗体的鼠标、键盘、输入法、绘制,各种消息,都来自于Qt的消息循环。以Windows操作系统为例,Qt接管Windows原生窗口消息,并翻译成Qt的消息,派发给程序下的各个子对象、子QWidget等,通过接管层,可以很好屏蔽不同平台之间的差异性,开发人员不需要关心Windows或者X11的消息的差异性,只需要搞清楚各个QEvent之间是什么含义。
最开始的Qt消息循环开始于QCoreApplication::exec()。用户创建出一个QCoreApplication,或者说更多情况下是QApplication,执行QCoreApplication::exec(),一个应用程序便开始了。QCoreApplication会不断从操作系统获取消息,并且分发给QObject。
如果没有消息循环,那么Qt的信号和槽无法完全使用,有些函数也无法正确执行。举个例子,通过QueuedConnection连接的信号,其实是将一个事件压入了消息循环,如果没有QCoreApplication::exec(),那么这个消息循环将永远无法派发到指定的对象。
二、什么是线程相关性
准确点来说,应该是指QObject的线程相关性。以Qt文档中的示意图来作说明:
当我们创建一个QObject时,它会与创建自己所在的线程绑定。它参与的消息循环,其实是它所在线程的消息循环,如上图所示。假如某个线程没有默认的QThread::exec(),那么该线程上的QObject则无法接收到事件。另外,如果两个不同线程的QObject需要相互通信,那么只能通过QueuedConnection的方式,异步通知对方线程,在下一轮消息循环处理QObject的消息。
QObject的线程相关性默认会和它的parent保持一致。如果一个QObject没有parent,那么可以通过moveToThread,将它的线程相关性切换到指定线程。
了解QObject的线程相关性非常重要,很多初学者常常分不清一个多线程中哪些QObject应该由主线程创建,哪些应该由工作线程创建,我的观点是,它参与哪个消息循环,就由哪个来创建。
正因为这样的特性,我们才可以理解什么叫做AutoConnection。通过AutoConnect连接的两个QObject,如果是在同一个线程,那么可以直接调用(DirectConnection),如果不是在同一个线程,那么就通过事件通知的方式(QueuedConnection)来调用。通过信号和槽、事件或者QueuedConnection方式来进行线程间的通讯,尤其是与UI线程通讯,永远是最优雅的方式之一。