Qt入门(9)——Qt中的线程支持
Qt对线程提供了支持,基本形式有独立于平台的线程类、线程安全方式的事件传递和一个全局Qt库互斥量允许你可以从不同的线程调用Qt方法。
警告:所有的GUI类(比如,QWidget和它的子类),操作系统核心类(比如,QProcess)和网络类都不是线程安全的。
QRegExp使用一个静态缓存并且也不是线程安全的,即使通过使用QMutex来保护的QRegExp对象。
启用线程支持
在Windows上安装Qt时,在一些编译器上线程支持是一个选项。
在Mac OS X和Unix上,线程支持可以当你在运行configure脚本时添加-thread选项就可以生效了。在Unix平台上,多线程程序必须用特殊的方式连接,比如使用特殊的libc,安装程序将会创建另外一个库libqt-mt并且因此线程程序必须和这个库进行连接(使用-lqt-mt)而不是标准的Qt库。
在两个平台上,你都应该定义宏QT_THREAD_SUPPORT来编译(比如,编译时使用-DQT_THREAD_SUPPORT)。在Windows上,这个通常可以在qconfig.h写一个条目来解决。
线程类
最重要的类是QThread,也就是说要开始一个新的线程,就是开始执行你重新实现的QThread::run()。这和Java的线程类很相似。
为了写线程程序,在两个线程同时希望访问同一个数据时,对数据进行保护是很必要的。因此这里也有一个QMutex类,一个线程可以锁定互斥量,并且在它锁定之后,其它线程就不能再锁定这个互斥量了,试图这样做的线程都会被阻塞直到互斥量被释放。例如:
class MyClass
{
public:
void doStuff( int ); private:
QMutex mutex;
int a;
int b;
}; // 这里设置a为c,b为c*2。 void MyClass::doStuff( int c )
{
mutex.lock();
a = c;
b = c * 2;
mutex.unlock();
}
这保证了同一时间只有一个线程可以进入MyClass::doStuff(),所以b将永远等于c * 2。
另外一个线程也需要在一个给定的条件下等待其它线程的唤醒,QWaitCondition类就被提供了。线程等待的条件QWaitCondition指出发生了什么事情,阻塞将一直持续到这种事情发生。当某种事情发生了,QWaitCondition可以唤醒等待这一事件的线程之一或全部。(这和POSIX线程条件变量是具有相同功能的并且它也是Unix上的一种实现。)例如:
#include <qapplication.h>
#include <qpushbutton.h> // 全局条件变量
QWaitCondition mycond; // Worker类实现
class Worker : public QPushButton, public QThread
{
Q_OBJECT public:
Worker(QWidget *parent = 0, const char *name = 0)
: QPushButton(parent, name)
{
setText("Start Working"); // 连接从QPushButton继承来的信号和我们的slotClicked()方法
connect(this, SIGNAL(clicked()), SLOT(slotClicked())); // 调用从QThread继承来的start()方法……这将立即开始线程的执行
QThread::start();
} public slots:
void slotClicked()
{
// 唤醒等待这个条件变量的一个线程
mycond.wakeOne();
} protected:
void run()
{
// 这个方法将被新创建的线程调用…… while ( TRUE ) {
// 锁定应用程序互斥锁,并且设置窗口标题来表明我们正在等待开始工作
qApp->lock();
setCaption( "Waiting" );
qApp->unlock(); // 等待直到我们被告知可以继续
mycond.wait(); // 如果我们到了这里,我们已经被另一个线程唤醒……让我们来设置标题来表明我们正在工作
qApp->lock();
setCaption( "Working!" );
qApp->unlock(); // 这可能会占用一些时间,几秒、几分钟或者几小时等等,因为这个一个和GUI线程分开的线程,在处理事件时,GUI线程不会停下来……
do_complicated_thing();
}
}
}; // 主线程——所有的GUI事件都由这个线程处理。
int main( int argc, char **argv )
{
QApplication app( argc, argv ); // 创建一个worker……当我们这样做的时候,这个worker将在一个线程中运行
Worker firstworker( 0, "worker" ); app.setMainWidget( &worker );
worker.show(); return app.exec();
}
只要你按下按钮,这个程序就会唤醒worker线程,这个线程将会进行并且做一些工作并且然后会回来继续等待被告知做更多的工作。如果当按钮被按下时,worker线程正在工作,那么就什么也不会发生。当线程完成了工作并且再次调用QWaitCondition::wait(),然后它就会被开始。
线程安全的事件传递
在Qt中,一个线程总是一个事件线程——确实是这样的,线程从窗口系统中拉出事件并且把它们分发给窗口部件。静态方法QThread::postEvent从线程中传递事件,而不同于事件线程。事件线程被唤醒并且事件就像一个普通窗口系统事件那样在事件线程中被分发。例如,你可以强制一个窗口部件通过如下这样做的一个不同的线程来进行重绘:
QWidget *mywidget;
QThread::postEvent( mywidget, new QPaintEvent( QRect(0, 0, 100, 100) ) );
这(异步地)将使mywidget重绘一块100*100的正方形区域。
Qt库互斥量
Qt库互斥量提供了从线程而不是事件线程中调用Qt方法的一种方法。例如:
QApplication *qApp;
QWidget *mywidget; qApp->lock(); mywidget->setGeometry(0,0,100,100); QPainter p;
p.begin(mywidget);
p.drawLine(0,0,100,100);
p.end(); qApp->unlock();
在Qt中没有使用互斥量而调用一个函数通常情况下结果将是不可预知的。从另外一个线程中调用Qt的一个GUI相关函数需要使用Qt库互斥量。在这种情况下,所有可能最终访问任何图形或者窗口系统资源的都是GUI相关的。使用容器类,字符串或者输入/输出类,如果对象只被一个线程使用就不需要任何互斥量了。
当进行线程编程时,需要注意的一些事情:
当使用Qt库互斥量的时候不要做任何阻塞操作。这将会冻结事件循环。
确认你锁定一个递归QMutex的次数和解锁的次数一样,不能多也不能少。
在调用除了Qt容器和工具类的任何东西之前锁定Qt应用程序互斥量。
谨防隐含地共享类,你应该避免在线程之间使用操作符=()来复制它们。这将会在Qt的未来主要的或次要的发行版本中进行改进。
谨防那些没有被设计为线程安全的Qt类,例如,QPtrList的应用程序接口就不是线程安全的并且如果不同的线程需要遍历一个QPtrList,它们应该在调用QPtrList::first()之前锁定并且在到达终点之后解锁,而不是在QPtrList::next()的前后进行锁定和解锁。
确认只在GUI线程中创建的继承和使用了QWidget、QTimer和QSocketNotifier的对象。在一些平台上,在某个不是GUI线程的线程中创建这样的对象将永远不会接受到底层窗口系统的事件。
和上面很相似,只在GUI线程中使用QNetwork类。一个经常被问到的问题是一个QSocket是否可以在多线程中使用。这不是必须得,因为所有的QNetwork类都是异步的。
不要在不是GUI线程的线程中试图调用processEvents()函数。这也包括QDialog::exec()、QPopupMenu::exec()、QApplication::processEvents()和其它一些。
在你的应用程序中,不要把普通的Qt库和支持线程的Qt库混合使用。这也就是说如果你的程序使用了支持线程的Qt库,你就不应该连接普通的Qt库、动态的载入普通Qt库或者动态地连接其它依赖普通Qt库的库或者插件。在一些系统上,这样做会导致Qt库中使用的静态数据变得不可靠了。
Qt入门(9)——Qt中的线程支持的更多相关文章
- Qt入门学习——Qt 5 帮助文档的使用
Qt入门学习——Qt 5 帮助文档的使用 学习图形界面开发,肯定离不开帮助文档的使用,因为它不像 C 语言那样就那么几个函数接口,图形接口的接口可以用海量来形容,常用的我们可能能记住,其它的真的没有必 ...
- Qt入门——使用QT+VS2008开发windows应用程序
1.文件->新建->项目 Qt4 Projects 右边已安装模板当中选择At Application. 确定 2.选择需要使用的QT库 下一步 3. “class name”:指定类的名 ...
- 【Qt开发】事件循环与线程 二
事件循环与线程 二 Qt 线程类 Qt对线程的支持已经有很多年了(发布于2000年九月22日的Qt2.2引入了QThread类),Qt 4.0版本的release则对其所有所支持平台默认地是对多线程支 ...
- QT中的线程与事件循环理解(2)
1. Qt多线程与Qobject的关系 每一个 Qt 应用程序至少有一个事件循环,就是调用了QCoreApplication::exec()的那个事件循环.不过,QThread也可以开启事件循环.只不 ...
- Qt中暂停线程的执行(主线程和工作线程共用一把锁,一旦主线程将它锁上,工作线程就无法运行了,这也是一个办法)
在线程中定义一个信号量: QMutex pause; 把run()函数中循环执行的部分用信号量pause锁住: void run() { while(1) { pause.lock ...
- qt 如何使用 lamda 表达式接收线程中发射的数据,并在里面更新 UI ?
Qt 信号和槽连接方式 常量 描述 Qt::AutoConnection (默认)如果接收方位于发出信号的线程中,则使用Qt::DirectConnection.否则,使用Qt::QueuedConn ...
- 第15.28节 PyQt(Python+Qt)入门学习:Model/View架构中的便利类QTableWidget详解
老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 一.引言 表格部件为应用程序提供标准的表格显示工具,在表格内可以管理基于行和列的数据项,表格中的最大 ...
- 第15.27节 PyQt(Python+Qt)入门学习:Model/View架构中的便利类QTreeWidget详解
老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 一.引言 树部件(Tree Widget)是Qt Designer中 Item Widgets(It ...
- 第15.26节 PyQt(Python+Qt)入门学习:Model/View架构中的便利类QListWidget详解
老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 一.概述 列表部件(List Widget)对应类QListWidget,是从QListView派生 ...
随机推荐
- Java基础知识强化05:不借助第三个变量实现两个变量互换
1. 不借助第三个变量实现两个变量互换 代码如下: package himi.hebao; /** * 不借助第三个变量实现,两个变量互换 * 这里利用^异或实现两个变量的互换 * @author A ...
- sqlserver 2008表分区操作
表分区操作步骤 1.设计表进行分区的方案,水平分区.垂直分区 a.水平切割将减少表的行数,这样可以将历史数据归档,减少表大小,提高访问速度. b.垂直切割将分为主表和从表方式,将主要的列字段存放在主表 ...
- 利用DIV,实现简单的网页布局
<html lang="en"><head> <meta charset="UTF-8"> <title>GIS ...
- java '相等'的比较.
我们知道对于操作符 "==",如果比较的是原生类型(primitive type),表示的是 '值本身'是否相等;而对于引用类型(reference type),表示的是 '对象的 ...
- PropertyPlaceholderConfigurer的用法(使用spring提供的类读取数据库配置信息.properties)
http://www.cnblogs.com/wanggd/archive/2013/07/04/3172042.html(写的很好)
- 浅析CSS中的haslayout
作为一名web开发人员,最大的希望不是自己的水平有多高,而是希望浏览器厂家能够统一标准,相信任何一个只要是接触过web程序开发的人员都有那样的感受,就是浏览器之间的兼容性问题总是让我们的工作平添诸多的 ...
- SGU 185.Two shortest (最小费用最大流)
时间限制:0.25s 空间限制:4M 题意: 在n(n<=400)个点的图中,找到并输出两条不想交的最短路.不存在输出“No sulotion”: Solution: 最小费用最大流 建图与po ...
- Flume研究心得
最近两天,仔细的看了一下Flume中央日志系统(版本号:1.3.X),Flume在本人看来,还是一个非常不错的日志收集系统的,其设计理念非常易用,简洁.并且是一个开源项目,基于Java语言开发,可以进 ...
- log4j 1.2配置(转载)
转载自:http://www.blogjava.net/kit-soft/archive/2009/08/28/292977.html 第一步:加入log4j-1.2.8.jar到lib下. 第二步: ...
- 基于Qt QGraphicsView的多点触摸绘图
本应用于基于QGraphicsView框架,实现多点触摸. 工程仅仅演示了多点触摸绘图,源自我前段时间一款基于Qt的绘图软件. 工程结构: kmp.h 定义了枚举 slide.h/cpp 定义了派生于 ...