代码之家  ›  专栏  ›  技术社区  ›  Aquarius_Girl

moveToThread vs从qt中的qthread派生

  •  22
  • Aquarius_Girl  · 技术社区  · 7 年前

    什么时候应该 moveToThread 优先于子类化 QThread ?

    This link 说明两种方法都有效。我应该在什么基础上决定这两种方法的用途?

    4 回复  |  直到 7 年前
        1
  •  16
  •   TheDarkKnight    7 年前

    我将着重讨论这两种方法之间的差异。没有一个通用的答案适用于所有的用例,所以很好地理解它们是什么来选择最适合您的用例。

    使用moveToThread()

    移动线程() 用于控制 对象的线程关联 ,这基本上意味着设置线程(或者更好的qt事件循环),对象将从中发出信号并执行其插槽。

    如您链接的文档所示,这可以用于在不同的线程上运行代码,基本上创建 假工人 ,编写要在 公用插槽 (在示例中 嫁妆() 插槽),然后使用 移动线程 将其移动到不同的事件循环。

    然后,连接到该插槽的信号被触发。因为发出信号的物体 控制器 在示例中)位于不同的线程中,并且信号通过排队连接连接到我们的DoWork方法,DoWork方法将在工作线程中执行。

    关键是你正在创建一个 新事件循环 ,由工作线程运行。因此,一旦Dowork时隙启动,整个事件循环将一直忙到退出,这意味着传入信号将排队。

    子类化qthread()

    qt文档中描述的另一种方法是对qthread进行子类化。在这种情况下,可以重写qthread::run()方法的默认实现,该方法创建一个事件循环,以运行其他内容。

    这种方法本身没有什么问题,尽管有几个陷阱。

    首先,编写不安全的代码非常容易,因为 () 方法是该类中唯一将在另一个线程上实际运行的方法。

    例如,您在构造函数中初始化了一个成员变量,然后在 () 方法,则在调用方的线程中初始化成员,然后在新线程中使用。

    对于任何可以从调用方调用或在run()内部调用的公共方法来说,情况都是一样的。

    同时,插槽将从调用方的线程执行(除非您做了一些非常奇怪的事情 移动线程(此) )导致额外的混乱。

    所以,这是可能的,但你真的是靠自己的方式,你必须格外注意。

    其他方法

    当然,这两种方法都有其他选择,这取决于您需要什么。如果在运行gui线程时只需要在后台运行一些代码,可以考虑使用 QtConcurrent::run() .

    但是,请记住qtconcurrent将使用全局 qthreadpool线程池 . 如果整个池都很忙(意味着池中没有可用的线程),您的代码将不会立即运行。

    另一种选择,如果你至少在C++ 11上使用的是较低级别的API,比如 std::thread .

        2
  •  8
  •   cbuchart    7 年前

    作为出发点:两者都不要。在大多数情况下,您有一个希望异步运行的工作单元。使用 QtConcurrent::run 为了这个。

    如果有一个对象对事件做出反应和/或使用计时器,则它是 QObject 这应该是非阻塞的,并进入一个线程,可能与其他对象共享。

    这样的对象还可以包装阻塞api。

    子类别化 QThread 在实践中从来没有必要。就像子类化 QFile . Q螺纹 是一个线程句柄。它包装系统资源。超载有点傻。

        3
  •  3
  •   Jeka    7 年前

    qthread是低级线程抽象,首先看高级api QtConcurrent 模块和 QRunnable

    如果这些都不适合你,那就读 this old article ,它告诉您应该如何使用qthread。将线程和在此线程中执行的任务看作一个单独的对象,不要将它们混合在一起。

    因此,如果需要编写自定义的、特定的或扩展的线程包装器,那么应该将qthread子类化。

    如果qobject派生类具有信号和插槽,则在其上使用moveToThread。

    在其他情况下,使用qtconcurrent、qrunnable和qthreadpoll。

        4
  •  0
  •   Marek R    7 年前

    简单的回答总是。 将对象移动到线程时:

    • 为代码编写测试很容易
    • 重构代码很容易(可以使用线程,但不必)。
    • 您不能将线程的功能与业务逻辑混合在一起
    • 对象生存期没有问题

    当你分类的时候 QThread

    • 编写测试比较困难
    • 对象清理过程可能会变得非常混乱,从而导致奇怪的错误。

    qt博客对该问题有完整的描述: You’re doing it wrong… .

    QtConcurrent::run 也很方便。

    请记住,默认情况下,当从其他线程对象发送信号时,插槽会尝试在线程之间跳转。有关详细信息,请参阅 Qt::ConnectionType