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

一、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

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



  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值