moveToThread vs deriving from QThread in Qt

前端 未结 4 1016
南笙
南笙 2021-02-01 17:07

When should moveToThread be preferred over subclassing QThread?

This link shows that both methods work. On what basis should I decide what to u

相关标签:
4条回答
  • 2021-02-01 17:21

    Simple answer is ALWAYS. When you move object to thread:

    • it is easy to write test for code
    • it is easy to refactor code (you can use thread but you don't have to).
    • you do not mix functionality of thread with business logic
    • there is no problem with object lifetime

    When you subclass QThread

    • it is harder to write test
    • object clean up process can get very confusing leading to strange errors.

    There is full description of the problem from Qt blog: You’re doing it wrong….

    QtConcurrent::run is also very handy.

    Please remember that by default slots are trying to jump between treads when signal is send from other thread object is assigned to. For details see documentation of Qt::ConnectionType.

    0 讨论(0)
  • 2021-02-01 17:25

    QThread is low level thread abstraction, first look at high level API QtConcurrent module and QRunnable

    If nothing of these is suitable for you, then read this old article, it tells how you should use QThread. Think about thread and task performed in this thread as a separate objects, don't mix them together.

    So, if you need to write come custom, specific or extended thread wrapper then you should subclass QThread.

    If you have QObject derived class with signals and slots, then use moveToThread on it.

    In other cases use QtConcurrent, QRunnable and QThreadPoll.

    0 讨论(0)
  • 2021-02-01 17:32

    I would focus on the differences between the two methods. There isn't a general answer that fits all use cases, so it's good to understand exactly what they are to choose the best that fits your case.

    Using moveToThread()

    moveToThread() is used to control the object's thread affinity, which basically means setting the thread (or better the Qt event loop) from which the object will emit signals and its slots will be executed.

    As shown in the documentation you linked, this can be used to run code on a different thread, basically creating a dummy worker, writing the code to run in a public slot (in the example the doWork() slot) and then using moveToThread to move it to a different event loop.

    Then, a signal connected to that slot is fired. Since the object that emits the signal (the Controller in the example) lives in a different thread, and the signal is connected to our doWork method with a queued connection, the doWork method will be executed in the worker thread.

    The key here is that you are creating a new event loop, run by the worker thread. Hence, once the doWork slot has started, the whole event loop will be busy until it exits, and this means that incoming signals will be queued.

    Subclassing QThread()

    The other method described in Qt's documentation is subclassing QThread. In this case, one overrides the default implementation of the QThread::run() method, which creates an event loop, to run something else.

    There's nothing wrong with this approach itself, although there are several catches.

    First of all, it is very easy to write unsafe code, because the run() method is the only one in that class that will be actually run on another thread.

    If as an example, you have a member variable that you initialize in the constructor and then use in the run() method, your member is initialized in the thread of the caller and then used in the new thread.

    Same story for any public method that could be called either from the caller or inside run().

    Also slots would be executed from the caller's thread, (unless you do something really weird as moveToThread(this)) leading to extra confusion.

    So, it is possible, but you really are on your own with this approach and you must pay extra attention.

    Other approaches

    There are of course alternatives to both approaches, depending on what you need. If you just need to run some code in background while your GUI thread is running you may consider using QtConcurrent::run().

    However, keep in mind that QtConcurrent will use the global QThreadPool. If the whole pool is busy (meaning there aren't available threads in the pool), your code will not run immediately.

    Another alternative, if you are at the least on C++11, is to use a lower level API such as std::thread.

    0 讨论(0)
  • 2021-02-01 17:36

    As a starting point: use neither. In most cases, you have a unit of work that you wish to run asynchronously. Use QtConcurrent::run for that.

    If you have an object that reacts to events and/or uses timers, it's a QObject that should be non-blocking and go in a thread, perhaps shared with other objects.

    Such an object can also wrap blocking APIs.

    Subclassing QThread is never necessary in practice. It's like subclassing QFile. QThread is a thread handle. It wraps a system resource. Overloading it is a bit silly.

    0 讨论(0)
提交回复
热议问题