QThread

来源:互联网 发布:阿里云服务器推荐 编辑:程序博客网 时间:2024/05/21 07:57

       在学习QThread之前,先考虑下何时需要线程?

         http://www.bogotobogo.com/cplusplus/multithreaded.php

1)  需要处理多任务,每个任务对应一个线程;

2)  当执行某个动作非常耗时,可以将该动作放在一个线程中处理,从而不会阻塞主线程。

一、难点及文章推荐:

        因为: 
        1) QThread 是用来管理线程的,它所依附的线程和它管理的线程并不是同一个东西。
        2) QThread 所依附的线程,就是执行 QThread t(0) 或 QThread * t=new QThread(0) 的线程。也就是咱们这儿的主线程
        3) QThread 管理的线程,就是 run 启动的线程。也就是次线程
        4) 因为QThread的对象依附在主线程中,所以他的slot函数会在主线程中执行,而不是次线程。
        问题:如何使某个non-GUI对象的signal, slot函数运行在次线程中?
        如果使自己定义的某个non-GUI对象继承QThread,那他的调用start()后,它的run函数会运行在次线程中。但是它的signal和slot函数仍运行在主线程。
        如果在在该non-GUI对象的构造中调用:moveToThread(this),则该对象的signal和slot函数将运行在次线程中,但不推荐使用这种方法。原因见文章3。
        推荐的方法见文章2。

        以下几篇文章总的来说都是围绕这个主题来讲解的。

        ThreadingBasics的Example3用设置signal和slot的connect方式来改变signal和slot的运行线程?

1、线程基础

        ttp://blog.csdn.net/dbzhang800/article/details/6554104 和官方文档:Threading basics
GUI Thread and Worker Thread
        As mentioned, each program has one thread when it is started. This thread is called the"main thread"(also known as the "GUI thread" in Qt applications). The Qt GUI must run in this thread. All widgets and several related classes, for example QPixmap, don't work in secondary threads. A secondary thread is commonly referred to as a"worker thread" because it is used to offload processing work from the main thread.
Using Threads
        There are basically two use cases for threads:
        1) Make processing faster by making use of multicore processors.
        2) Keep the GUI thread or other time critical threads responsive by offloading long lasting processing or blocking calls to other threads.
QObject and Threads
        The anatomy of QThread is quite interesting:
        1) QThread does not live in the new thread where run() is executed. It lives in the old thread.
        2) Most QThread methods are the thread's control interface and are meant to be called from the old thread. Do not move this interface to the newly created thread using moveToThread(); i.e., calling moveToThread(this) is regarded as bad practice.
        3) exec() and the static methods usleep(), msleep(), sleep() are meant to be called from the newly created thread.
        4) Additional members defined in the QThread subclass are accessible by both threads.
        注:但moveToThread(this)在该文档中的Example4中有使用。
       Which Qt Thread Technology Should You Use?
       The right solution depends on the purpose of the new thread as well as on the thread's lifetime.

        注意:Threading basics的Example4--A Permanent Thread中对QThread的使用方法是被文章2、3中的观点所批判的,因为其使用了:moveToThread(this)。

2、QThread 使用探讨

         http://hi.baidu.com/dbzhang800/item/1e931317d37d71dcbe904247 
        1) QThread 是用来管理线程的,它所依附的线程和它管理的线程并不是同一个东西。
        2) QThread 所依附的线程,就是执行 QThread t(0) 或 QThread * t=new QThread(0) 的线程。也就是咱们这儿的主线程
        3) QThread 管理的线程,就是 run 启动的线程。也就是次线程
        4) 因为QThread的对象依附在主线程中,所以他的slot函数会在主线程中执行,而不是次线程。
        除非:QThread 对象依附到次线程中(通过movetoThread);slot 和信号是直接连接,且信号在次线程中发射。但上两种解决方法都不好,因为QThread不是这么用的(Bradley T. Hughes)

        文章然后讨论了在次线程中使用信号和槽的几种方法。文中推荐的方法如下:
        定义一个普通的QObject派生类,然后将其对象move到QThread中。使用信号和槽时根本不用考虑多线程的存在。也不用使用QMutex来进行同步,Qt的事件循环会自己自动处理好这个。

        尝试用该方法重写Threading basics中的Example4.

3、QThread 的使用方法

        http://hi.baidu.com/dbzhang800/item/c14c97dd15318d17e1f46f41 
        QThread 应该被看做是操作系统线程的接口或控制点,而不应该包含需要在新线程中运行的代码。需要运行的代码应该放到一个QObject的子类中,然后将该子类的对象moveToThread到新线程中

4、官方文档:Threads and QObjects

5、QThread与SLOT

        http://my.oschina.net/hevakelcj/blog/122670

6、Using QThreadWithout Subclassing

 http://codethis.wordpress.com/2011/04/04/using-qthread-without-subclassing/

        The first thing you need to know about using QThread is,a QThread object is not a thread.QThread is a class used for managing a thread; it is not itself a thread. The only method onQThread that runs on a separate thread is “run”.

        The second thing you need to know about using QThread is,as with all QObject subclasses, a QThread object has affinity to the thread in which it is instantiated. If you subclass QThread and add your own slots, you may be surprised to learn that these slots will actually run on the main thread. This also means you cannot use the QThread object as the parent of a QObject instance that has affinity to the thread (i.e., one created within “run”).

        And lastly, you need to know that only the main (GUI) thread can access GUI elements(QWidgets). The method of communicating between the thread and the GUI is signals and slots. If you don’t know, by default an object’s slots are run on he thread to which the object has affinity. This is done using the event loop.

        Unfortunately,until Qt 4.4, QThread was an abstract class. The “run” method was pure virtual.And, even though this is no longer the case, the documentation still shows an example of using QThread by subclassing. 

        公司里用的仍是Qt4.3,因为run函数是纯虚函数,因此QThread是抽象基类,知在Qt4.3中QThread无法实例化。解决方法:可以定义一个集成QThread的Thread类,然后重载run函数,并在run函数里执行exec()进入事件循环。在其他的需要使用线程的类中使用Thread类。是否可行?

二、主要知识点

1、QThread

        QObject is reentrant. Most of its non-GUI subclasses, such as QTimer, QTcpSocket, QUdpSocket, QFtp, and QProcess, are also reentrant, making it possible to use these classes from multiple threads simultaneously. 
        Although QObject is reentrant, the GUI classes, notably QWidget and all its subclasses,  are not reentrant. They can only be used from the main thread.

        Another way to make code run in a separate thread, is to subclass QThread and reimplement run(). 
        1)要使用线程的类必须是non-GUI类,也就是该non-GUI类才能使用线程;
        2)QThread::isRunning
        Returns true if the thread is running; otherwise returns false.
        该函数的含义是:线程是否正在运行。在第一次start()之前,isRunning()返回的值是false;调用start()之后,isRunning()返回true;等待run()运行完毕,isRunning()又返回false。

2、QMutex

        When you call lock() in a thread, other threads that try to call lock() in the same place will block until the thread that got the lock calls unlock(). A non-blocking alternative to lock() is try Lock(). For instance:
Void method(){mutex.lock();number++;mutex.unlock();}

3、QMutexLocker

        It is usually best to use a mutex with a QMutexLocker since this makes it easy to ensure that locking and unlocking are performed consistently.
QMutexLocker should be created within a function where a QMutex needs to be locked. The mutex is locked when QMutexLocker is created. You can unlock and relock the mutex with unlock() and relock(). If locked, the mutex will be unlocked when the QMutexLocker is destroyed.
        QMutexLocker的作用就是为了简化QMutex的load, unload操作。通常在函数开始处执行QMutexLocker locker(&mutex),则该mutex将一直是lock状态,知道被unlock或者locker被销毁。
        注意:只要在多线程代码(QThread的subclass)里改变公共资源时,通常都需要再这块代码前后用QMutex.lock(), unlock()或者在该块代码前用QMutexLocker做保护。


0 0
原创粉丝点击