• Qthread实现多线程操作


    受不了xxxx恶心人的行为,遂搬迁至博客园。
    始发:2014-08-26 17:56:37
    

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

  • 相关阅读:
    FFmpeg在JAVA中的使用以及Process.waitFor()引发的阻塞问题
    分析自己遇到的Excel导出报NullpointException问题
    C# 获取文件路径
    List的方法和属性 方法或属性 作用
    asp.net发布到IIS中出现错误:处理程序“PageHandlerFactory-Integrated”在其模块列表中有一个错误模块“ManagedPipelineHandler”
    .NET 垃圾回收与内存泄漏
    .NET多线程总结和实例介绍
    C#中释放数据库连接资源
    PHP
    sqlconnection dispose()与close()的区别
  • 原文地址:https://www.cnblogs.com/rockyching2009/p/13139801.html
Copyright © 2020-2023  润新知