首页 > 编程语言 > 详细

[Qt学习篇]Qthread实现多线程操作

时间:2014-08-26 19:44:46      阅读:552      评论:0      收藏:0      [点我收藏+]

一、QThread类概述                                       

QThread类为用户管理多线程提供了一种平台无关的途径。

#include <QThread>

继承自QObject类


二、QThread类详述                                       

QThread对象在程序内部进行控制线程的管理,QThread起始于run()函数额执行。默认情况下,run()通过调用exec()启动事件循环(event loop),并在线程内部执行Qt 的事件循环。

以下示例通过QObject::moveToThread()调用把worker对象添加到线程中运行:

class Worker : public QObject
 {
     Q_OBJECT
     QThread workerThread;
 
 public slots:
     void doWork(const QString str) {
         // ...
         emit resultReady(result);
     }
 
 signals:
     void resultReady(const QString &result);
 };
 
 class Controller : public QObject
 {
     Q_OBJECT
     QThread workerThread;
 public:
     Controller() {
         Worker *worker = new Worker;
         worker->moveToThread(&workerThread);
         connect(workerThread, SIGNAL(finished()), worker, SLOT(deleteLater()));
         connect(this, SIGNAL(operate(QString)), worker, SLOT(doWork(QString)));
         connect(worker, SIGNAL(resultReady(QString)), this, SLOT(handleResults(QString)));
         workerThread.start();
     }
     ~Controller() {
         workerThread.quit();
         workerThread.wait();
     }
 public slots:
     void handleResults(const QString &);
 signals:
     void operate(const QString &);
 };

Worker槽中的代码以后就在一个独立的线程中运行。你可以按自己意愿,把Worker槽(slots )连接到任何对象的信号(signal)上。得益于队列连接(queued connections) 机制(一个事件被派发到接收者所在线程的事件循环,当事件被传递,相应的槽随之被激活),在不同对象间进行信号和槽的连接是安全的。


另外一种实现多线程的方式是继承QThread类,并重新实现run()函数,例如:

class Thread : public QThread
{   
    Q_OBJECT
public:
    Thread();
    void setMessage(const QString &message);
    void stop();
protected:
    void run();
private:
    QString messageStr;
    volatile bool stopped;
    QUdpSocket *udpSpcket;
};
class ThreadDialog : public QDialog
{
    Q_OBJECT
public:
    ThreadDialog(QWidget *parent = 0);
protected:
    void closeEvent(QCloseEvent *event);
private slots:
    void startOrStopThreadA();
    void startOrStopThreadB();
private:
    Thread threadA;
    Thread threadB;
    QPushButton *threadAButton;
    QPushButton *threadBButton;
};

注意

1、当run()函数返回的以后,线程会退出(exit)。如果没有调用exec()函数,该线程中不存在任何运行状态的事件循环(event loop)。

2、重要的是,QThread对象通常存在于(lives in)创建他的线程中,而不是它管理的线程中。这意味着,QThread的槽是在它存在的线程(home thread)的上下文中被执行,而不是它管理的线程的上下文中。基于这一点,在QThread子类中实现新的槽是容易出错所以是不被提倡的。

3、如果使用其他方法(technique)在不同对象间进行交互,而不是队列性的信号-槽(signal/slot)机制,那么在多线程程序中就要预先警惕可能出现的问题。

4、GUI对象的线程必须存在于主线程(main thread)中。


三、管理QThread                                      

Managing threads

当线程开始运行(started())、执行完毕(finished())、终止(terminated())的时候,QThread通过信号()进行通知;反过来,也可以调用isFinished()isRunning()查询线程的状态。

要想停止(stop)线程,可以通过调用exit()quit()实现,在极端情况下,可以调用terminate()强制终止一个执行状态的线程——但是这样比较危险,并不提倡,使用setTerminationEnabled()函数可以使能/禁止terminate()函数。


Qt 4.8以后,通过把finished()信号连接到QObject::deleteLater()槽上,可以在线程结束后删除(deallocate)对象。


使用wait()可以阻塞调用线程,直到其他线程执行结束(也可以指定一个超时时间)。


静态(static)函数currentThreadId()currentThread()返回当前执行线程的的标识符(identifiers),


在线程启动前调用setObjectName()可以给线程指定一个名字,作为和其他线程的区别标识。如果没有调用setObjectName(),将以线程对象运行时类型的类名作为线程的名字。比如,下面例子中,线程的名字是RenderThread:

class RenderThread : public QThread
{
     Q_OBJECT
 public:
     RenderThread(QObject *parent = 0);
     ~RenderThread();
     void render(double centerX, double centerY, double scaleFactor, QSize resultSize); 

 signals:
     void renderedImage(const QImage &image, double scaleFactor);
 protected:
     void run();
 private:
     uint rgbFromWaveLength(double wave);
     QMutex mutex;
     QWaitCondition condition;  
};
注意:这种规则目前不适用于在Windows闪编译的release。

QThread类提供了static类型,平台无关的sleep函数:sleep()msleep()usleep(),经度分别是秒、毫秒、微秒。

注意:一般来讲,wait()sleep()应该是不必要的(unnecessary),因为Qt是基于事件驱动(event-driven)的架构。使用wait()的时候,考虑下finished(),sleep()时,考虑下QTimer。


四、QThread优先级                                  

enum Qthread::Priority

常量

描述

QThread::IdlePriority

0

没有其他线程运行时才进行调度

QThread::LowestPriority

1

不比LowPriority调度频繁

QThread::LowPriority

2

不比NormalPriority调度频繁

QThread::NormalPriority

3

操作系统的默认优先级

QThread::HighPriority

4

比NormalPriority调度频繁

QThread::HighestPriority

5

HighPriority调度频繁

QThread::TimeCriticalPriority

6

尽可能频繁的进行调度

QThread::InheritPriority

7

使用和创建自己的线程同样的优先级,这是默认属性



[Qt学习篇]Qthread实现多线程操作

原文:http://blog.csdn.net/u013686019/article/details/38851353

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!