QT核心编程之Qt线程是本节要介绍的内容,QT核心编程我们要分几个部分来介绍,想参考更多内容,请看末尾的编辑推荐进行详细阅读,先来看本篇内容。

Qt线程提供了支持,它引入了一些基本与平台无关的线程类、线程安全传递事件的方式和全局Qt库互斥量允许你从不同的线程调用Qt的方法。Qt中与线程应用相关的类如表6所示。

表6 Qt中与线程相关的类

使用线程需要Qt提供相应的线程库的支持,因此,在编译安装Qt时,需要加上线程支持选项。

当在Windows操作系统上编译Qt时,线程支持是在一些编译器上的一个选项。在Windows操作系统上编译应用程序时,通过在qconfig.h文件中增加一个选项来解决来解决这个问题。

在Mac OS X和Unix上编译Qt时,你应在运行configure脚本时添加-thread选项。在Unix平台上,多线程程序必须用特殊的线程支持库连接,多线程程序必须连接线程支持库libqt-mt,而不是标准的Qt库。编译应用程序时,你应该使用宏定义QT_THREAD_SUPPORT来编译(如:编译时使用-DQT_THREAD_SUPPORT)。

1、线程类QThread

在 Qt中提供了QThread线程类,它提供了创建一个新线程的方法。线程通过重载 QThread::run()函数开始执行的,这一点与Java中的线程类相似。

示例1:一个简单的线程

下面的例子实现了一个简单的继承自QThread的用户线程类,并运行2个线程,线程b在线程a运行完后运行。代码列出如下:

  1. class MyThread : public QThread {
  2. public:    virtual void run();
  3. };
  4. void MyThread::run() //运行线程{
  5. for( int count = 0;
  6. count < 20; count++ ) {
  7. sleep( 1 );
  8. qDebug( "Ping!" );
  9. }
  10. }
  11. int main(){
  12. MyThread a;
  13. MyThread b;
  14. a.start(); //通过调用run()函数来执行
  15. b.start();
  16. a.wait();
  17. b.wait();
  18. }

只有一个线程类是不够的,对于支持多线程的程序来说,还需要保护两个不同的线程对数据的同时访问,因此 Qt 提供了QMutex 类,一个线程可以锁住互斥量,当互斥量被锁住时,将阻塞其它线程访问临界数据,直到这个线程释放互斥量。这样,可以保护临界数据一次只能被一个线程访问。

Qt库互斥量(qApp->lock()和qApp->unlock())是在访问Qt的GUI界面资源时用到的互斥量。在 Qt中没有使用互斥量而调用一个函数通常会导致不可预知的行为。从另外一个线程中调用Qt的一个GUI相关函数需要使用Qt库互斥量。在这种情况下,所有访问图形或窗口系统资源的函数都与GUI相关。如果对象仅被一个线程访问,使用容器类,字符串或者输入/输出类不需要任何互斥量。

2、线程安全的事件传递

在Qt中,一个线程总是一个事件线程,线程从窗口系统中拉出事件并且把它们分发给窗口部件。静态方法QThread::postEvent从线程中邮递事件,而不是从事件线程。事件线程被唤醒并且事件象一个正常窗口系统的事件一样在事件线程中被分发。例如,你可以从不同的线程强制一个窗口部件进行重绘,方法如下:

  1. QWidget *mywidget;QThread::postEvent( mywidget, new QPaintEvent( QRect(0, 0, 100, 100) ) );

上述代码将异步地使mywidget在它区域中重绘一块100*100的正方形区域。

另外,还需要一些机制使得处于等待状态的线程在给定条件下被唤醒。QWaitCondition 类就提供了这种功能。线程等待的条件QWaitCondition满足,QWaitCondition表明发生了什么事情,它阻塞直到这件事情发生。当发生给定的事情时,QWaitCondition 将唤醒等待该事情的所有线程或者唤醒任意一个被选中的线程。(这和POSIX线程条件变量具有相同功能,是Unix上的一种实现。)

示例2:QWaitCondition类应用

下面这个例子的功能是:当你按下按钮,这个程序就会唤醒worker线程,这个线程在按钮上显示工作状态:等待(Waiting)还是正在工作(Working)。当按钮被按下时,worker线程正在工作,那么对线程不产生影响。当run函数再次循环到mycond.wait()时,线程阻塞并等待。当按钮再被按下时,触发slotClicked()函数运行,唤醒等待的线程。

  1. #include <qapplication.h>
  2. #include <qpushbutton.h> // 全局条件变量
  3. QWaitCondition mycond; // Worker类实现
  4. class Worker : public QPushButton, public QThread{
  5. Q_OBJECT public:    Worker(QWidget *parent = 0, const char *name = 0) : QPushButton(parent, name) {
  6. setText("Start Working");         // 将QPushButton继承来的信号与槽slotClicked()连接起来
  7. connect(this, SIGNAL(clicked()), SLOT(slotClicked()));         // 调用从QThread继承来的start()方法开始线程的执行
  8. QThread::start();
  9. }
  10. public slots:    void slotClicked()  {   // 唤醒等待这个条件变量的一个线程
  11. mycond.wakeOne();
  12. }
  13. protected:    void run() //重载run函数    {
  14. while ( TRUE ) {            // 锁定应用程序互斥锁,并且设置窗口标题来表明我们正在等待开始工作
  15. qApp->lock();
  16. setCaption( "Waiting" );
  17. qApp->unlock();             // 等待直到我们被告知可以继续
  18. mycond.wait();            // 如果到了这里,表示我们已经被另一个线程唤醒
  19. qApp->lock();
  20. setCaption( "Working!" );// 设置标题,表示正在工作
  21. qApp->unlock();
  22. }
  23. }
  24. };
  25. int main( int argc, char **argv ){
  26. QApplication app( argc, argv );     // 创建一个worker
  27. Worker firstworker( 0, "worker" );
  28. app.setMainWidget( &worker ); //将worker设置为应用程序的主窗口
  29. worker.show();
  30. return app.exec();
  31. }

当进行线程编程时,需要注意的一些事项:

(1)在持有Qt库互斥量时不要做任何阻塞操作。这将冻结事件循环。

(2)确认你锁定一个递归QMutex的次数等于解锁的次数,不能多也不能少。

(3)在调用除了Qt容器和工具类外的任何东西之前锁定Qt应用程序互斥量。

(4)谨防隐含的共享类,如果你需要在线程之间指定它们,你应该用detach()分离它们。

(5)小心没有被设计成线程安全的Qt类,例如,QPtrList的API接口不是线程安全的,并且如果不同的线程需要遍历一个QPtrList,它们应该在调用QPtrList::first()之前锁住,在到达终点后解锁。

(6)确信仅在GUI线程中创建继承自QWidget、QTimer和QSocketNotifier的对象。在一些平台上,创建在线程中而不是GUI线程的对象永远不会接收到底层窗口系统的事件。

(7)和上面很相似,只在GUI线程中使用QNetwork类。因为所有的QNetwork类都是异步的,没必要把QSocket用在多线程中。

(8)永远不要尝试在不是GUI线程线程中调用processEvents()函数。这也包括QDialog::exec()、QPopupMenu::exec()、QApplication::processEvents()和其它一些函数。

(9)在你的应用程序中,不要把普通的Qt库和支持线程Qt库混合使用。这意味着如果你的程序使用了支持线程Qt库,你就不能连接普通的Qt库、动态的载入普通Qt库或者动态地连接其它依赖普通Qt库的库或者插件。在一些系统上,这样做会导致Qt库中使用的静态数据崩溃。

小结:QT核心编程之Qt线程 的内容介绍完了,希望本节内容随你有所帮助,如果需要更多资料请参考编辑推荐。

QT核心编程之Qt线程 (c)的更多相关文章

  1. python并发编程之threading线程(一)

    进程是系统进行资源分配最小单元,线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.进程在执行过程中拥有独立的内存单元,而多个线程共享内存等资源. 系列文章 py ...

  2. [转]c++多线程编程之pthread线程深入理解

    多线程编程之pthread线程深入理解         Pthread是 POSIX threads 的简称,是POSIX的线程标准.           前几篇博客已经能给你初步的多线程概念.在进一 ...

  3. 三、VIP课程:并发编程专题->01-并发编程之Executor线程池详解

    01-并发编程之Executor线程池详解 线程:什么是线程&多线程 线程:线程是进程的一个实体,是 CPU 调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系 ...

  4. python并发编程之Queue线程、进程、协程通信(五)

    单线程.多线程之间.进程之间.协程之间很多时候需要协同完成工作,这个时候它们需要进行通讯.或者说为了解耦,普遍采用Queue,生产消费模式. 系列文章 python并发编程之threading线程(一 ...

  5. 界面编程之QT绘图和绘图设备20180728

    /*******************************************************************************************/ 一.绘图 整 ...

  6. 界面编程之QT窗口系统20180726

    /*******************************************************************************************/ 一.坐标系统 ...

  7. 界面编程之QT的线程20180731

    /*******************************************************************************************/ 一.为什么需 ...

  8. 界面编程之QT的事件20180727

    /*******************************************************************************************/ 一.事件 1 ...

  9. 界面编程之QT的Socket通信20180730

    /*******************************************************************************************/ 一.linu ...

随机推荐

  1. Android学习笔记-Dialog详解

    1.对话框的使用 1.1AlertDialog的显示 简单对话框以及监听的设置:重点掌握三个按钮(也就是三上单词): PositiveButton(确认按钮);NeutralButton(忽略按钮) ...

  2. Linux下的cut选取命令详解

    定义 正如其名,cut的工作就是“剪”,具体的说就是在文件中负责剪切数据用的.cut是以每一行为一个处理对象的,这种机制和sed是一样的 剪切依据 cut命令主要是接受三个定位方法: 第一,字节(by ...

  3. java getEnv不区分大小写 getProperty区分大小写

    System.out.println(System.getenv("JAVA_HOME")); System.out.println(System.getenv("Pat ...

  4. SUSE linux ,liveUSB制作方法

    下载了ubuntu 11.04,ubuntu11.10,fedora15,kubuntu 11.04,linuxmint-11,还有suse的kde和gnome的桌面版镜像,其他的都很方便的做成了li ...

  5. TPARAMS和OLEVARIANT相互转换

    所谓的“真3层”有时候是需要客户端上传数据集的TPARAMS到中间件的. 现在,高版本的DATASNAP的远程方法其实也是直接可以传输TPARAMS类型的变量,但是DELPHI7(七爷).六爷它们是不 ...

  6. UVaLive 6697 Homework Evaluation (DP)

    题意:给出一个长字符串,再给一个短字符串,进行匹配,如果第i个恰好匹配,则 +8,:如果不匹配,可以给长或短字符串添加-,先后匹配,这样-3, 连续的长字符串添加-,需要减去一个4:也可不给添加-,则 ...

  7. redis的发布订阅模式

    概要 redis的每个server实例都维护着一个保存服务器状态的redisServer结构 struct redisServer {     /* Pubsub */     // 字典,键为频道, ...

  8. easymock入门贴

    from:http://macrochen.iteye.com/blog/298032 关于EasyMock常见的几个问题, 这里(http://ozgwei.blogspot.com/2007/06 ...

  9. Android Studio 错误 Duplicate files copied in APK META-INF/LICENSE.txt

    1 .Duplicate files copied in APK META-INF/LICENSE.txt   android { packagingOptions { exclude 'META-I ...

  10. eclipse界面语言的切换方法

    很久以前在我一个朋友的blog上看到过关于eclipse中英文语言界面切换的方法,觉得挺不错,后来自己也用过几次 现在想想,这个方法真的很不错,刚才又在自己机器上做了几次试验,发现eclipse事实上 ...