Qt中的多线程技术

Multithreading Technologies in Qt

Qt中的多线程技术

Qt offers many classes and functions for working with threads. Below are four different approaches that Qt programmers can use to implement multithreaded applications.

Qt提供许多类和函数用于支持多线程工作。下面是Qt程序可用于多线程技术的四种方式。

QThread: Low-Level API with Optional Event Loops

QThread:对事件循环操作的低级别API

QThread is the foundation of all thread control in Qt. EachQThread instance represents and controls one thread.

QThread can either be instantiated directly or subclassed. Instantiating aQThread provides a parallel event loop, allowingQObject slots to be invoked in a secondary thread. Subclassing aQThread allows the application to initialize the new thread before starting its event loop, or to run parallel code without an event loop.

See the QThread class reference and the threading examples for demonstrations on how to useQThread.

QThread是线程控制的基础。每个QThread实例代表和控制一个线程。

QThread可以直接或通过子类实例化。实例化一个线程提供一个平行的事件循环,允许QObject槽函数在第二个线程中调用。QThread的子类允许程序在其事件循环前初始化新线程,或不使用事件循环而直接平行运行代码。

使用QThread,参见 QThread class reference 和 threading examples 文档。

QThreadPool and QRunnable: Reusing Threads

QThreadPool和QRunnable:重用线程

Creating and destroying threads frequently can be expensive. To reduce this overhead, existing threads can be reused for new tasks.QThreadPool is a collection of reuseable QThreads.

To run code in one of aQThreadPool's threads, reimplementQRunnable::run() and instantiate the subclassedQRunnable. UseQThreadPool::start() to put theQRunnable in theQThreadPool's run queue. When a thread becomes available, the code withinQRunnable::run() will execute in that thread.

Each Qt application has a global thread pool, which is accessible throughQThreadPool::globalInstance(). This global thread pool automatically maintains an optimal number of threads based on the number of cores in the CPU. However, a separateQThreadPool can be created and managed explicitly.

频繁的创建和销毁线程的开销高。为了降低这种开销,现有的线程可以被新任务重用。QThreadPool是可重用QThread的集合。

运行QTreadPool的一个线程的代码,重新实现QRunnable::run()以及实例化QRunnable子类。使用QThreadPool::start()将QRunnable放入QThreadPool的运行队列中。当一个线程可用时,在QRunnable::run()中的代码将会在这个线程中运行。

每个Qt程序都有一个全局线程池(global thread pool),可以通过QThreadPool::globalInstance()获得。这个全局线程池根据CPU的核心数,自动地维持线程的最佳个数。但是,一个单独的QTheadPool可以被明确的创建和管理。

Qt Concurrent: Using a High-level API

Qt Concurrent: 使用高级别API

The Qt Concurrent module provides high-level functions that deal with some common parallel computation patterns: map, filter, and reduce. Unlike usingQThread andQRunnable, these functions never require the use oflow-level threading primitives such as mutexes or semaphores. Instead, they return aQFuture object which can be used to retrieve the functions' results when they are ready.QFuture can also be used to query computation progress and to pause/resume/cancel the computation. For convenience,QFutureWatcher enables interactions withQFutures via signals and slots.

Qt Concurrent's map, filter and reduce algorithms automatically distribute computation across all available processor cores, so applications written today will continue to scale when deployed later on a system with more cores.

This module also provides theQtConcurrent::run() function, which can run any function in another thread. However,QtConcurrent::run() only supports a subset of features available to the map, filter and reduce functions. TheQFuture can be used to retrieve the function's return value and to check if the thread is running. However, a call toQtConcurrent::run() uses one thread only, cannot be paused/resumed/canceled, and cannot be queried for progress.

See the Qt Concurrent module documentation for details on the individual functions.

Qt Concurrent 模块提供……。与使用QThread和QRunnable不同,这些功能绝不需要使用低级的线程原语( threading primitives ),比如mutexes或semaphores。替代地,它们返回一个QFuture对象,可以在函数结果就绪时,检索之。QFuture也可以用于查询计算进展,暂停、重开、取消计算。为了方便,QFutureWatcher可以通过信号和槽函数与QFuture交互。

Qt Concurrent的map、filter和reduce算法自动分配计算到可用的处理器核心,所以……。

这个模块也提供QtConcurrent::fun()方法,可以用于在另外的线程中运行任何函数。但是QtConcurrent::run()只支持map,filter,和reduce功能的特性的一部分。QFuture可以用于检索函数的返回值,并检查线程是否在运行。但是,调用一次QtConcurrent::run()只使用一个线程,不能被暂停、重开、取消,也不能被进程查询。

详见……。

WorkerScript: Threading in QML

The WorkerScript QML type lets JavaScript code run in parallel with the GUI thread.

Each WorkerScript instance can have one .js script attached to it. When WorkerScript::sendMessage() is called, the script will run in a separate thread (and a separateQML context). When the script finishes running, it can send a reply back to the GUI thread which will invoke the WorkerScript::onMessage() signal handler.

Using a WorkerScript is similar to using a worker QObject that has been moved to another thread. Data is transferred between threads via signals.

See the WorkerScript documentation for details on how to implement the script, and for a list of data types that can be passed between threads.

Choosing an Appropriate Approach

选择一个合适的方案

As demonstrated above, Qt provides different solutions for developing threaded applications. The right solution for a given application depends on the purpose of the new thread and the thread's lifetime. Below is a comparison of Qt's threading technologies, followed by recommended solutions for some example use cases.

如上所示,Qt提供了开发多线程程序的多种解决方案。要根据新线程的目的和生命周期来决定适合的解决方案。下面是各个Qt多线程技术的对比,以及推荐的应用情况的例子。

Comparison of Solutions


Feature

QThread

QRunnable andQThreadPool

QtConcurrent::run()

Qt Concurrent (Map, Filter, Reduce)

WorkerScript

Language

C++

C++

C++

C++

QML

Thread priority can be specified

优先级是否可以指定

Yes

Yes

     

Thread can run an event loop

是否可以运行事件循环

Yes

       

Thread can receive data updates through signals

线程是否可以通过信号更新数据

Yes (received by a worker QObject)

     

Yes (received by WorkerScript)

Thread can be controlled using signals

线程是否可以通过信号控制

Yes (received by QThread)

   

Yes (received by QFutureWatcher)

 

Thread can be monitored through a QFuture

线程是否可以通过QFuture监视

   

Partially

Yes

 

Built-in ability to pause/resume/cancel

     

Yes

 

Example Use Cases


Lifetime of thread

线程生命周期

Operation

操作

Solution

解决方案

One call

一次性

Run a new linear function within another thread, optionally with progress updates during the run.

在新的线程中运行一个新的线性的函数,可在运行期间更新进度。

Qt provides different solutions:

Qt提供了不同解决方案:

  • Place the function in a reimplementation of QThread::run() and start the QThread. Emit signals to update progress. OR
  • Place the function in a reimplementation of QRunnable::run() and add the QRunnable to a QThreadPool. Write to a thread-safe variable to update progress. OR
  • Run the function using QtConcurrent::run(). Write to a thread-safe variable to update progress.
  • 将函数在 QThread::run() 中重新实现,并启动 QThread 。通过发射信号更新进度。或
  • 将函数在 QThread::run() 中重新实现,并将 QRunnable 加入一个 QThreadPool 。写一个线程安全变量用于更新进度。或
  • 使用 QtConcurrent::run() 运行函数。写一个线程安全变量用于更新进度。

One call

一次性

Run an existing function within another thread and get its return value.

在新的线程运行一个已经存在的函数,并得到其返回值。

Run the function using QtConcurrent::run(). Have a QFutureWatcher emit the finished() signal when the function has returned, and callQFutureWatcher::result() to get the function's return value.

使用 QtConcurrent::run() 运行函数。当函数有返回值时, QFutureWatcher 会发送 finished() 信号,并调用 QFutureWatcher::result() 获得函数返回值。

One call

一次性

Perform an operation on all items of a container, using all available cores. For example, producing thumbnails from a list of images.

需要操作一个容器中所有的项。使用处理器所有可用的核心。一个常见的例子是从图像列表生成缩略图。

Use Qt Concurrent's QtConcurrent::filter() function to select container elements, and theQtConcurrent::map() function to apply an operation to each element. To fold the output into a single result, useQtConcurrent::filteredReduced() andQtConcurrent::mappedReduced() instead.

使用 Qt Concurrent 的 QtConcurrent::filter() 选择包含的元素, QtConcurrent::map() 将会把操作应用到所选的每个元素。要将输出折叠到一个信号结果,使用QtConcurrent::filteredReduced() 和 QtConcurrent::mappedReduced() 作为替代。

One call/Permanent

一次性/永久

Perfrom a long computation in a pure QML application, and update the GUI when the results are ready.

Place the computation code in a .js script and attach it to a WorkerScript instance. Call sendMessage() to start the computation in a new thread. Let the script call WorkerScript::sendMessage() too, to pass the result back to the GUI thread. Handle the result inonMessage and update the GUI there.

Permanent

永久

Have an object living in another thread that can perform different tasks upon request and/or can receive new data to work with.

需要一个对象在另一个线程生存,可以执行各种不同的任务请求以及/或可以接收新的数据用来处理。

Subclass a QObject to create a worker. Instantiate this worker object and aQThread. Move the worker to the new thread. Send commands or data to the worker object over queued signal-slot connections.

继承QObject创建工作者类。实例化工作者和一个 QThread 。将工作者移入新线程。通过队列信号槽连接,给工作者发送命令或数据。

Permanent

永久

Repeatedly perform an expensive operation in another thread, where the thread does not need to receive any signals or events.

在新线程中重复地执行繁重的操作,而不需要接收任何信号和事件。

Write the infinite loop directly within a reimplementation ofQThread::run(). Start the thread without an event loop. Let the thread emit signals to send data back to the GUI thread.

直接在 QThread::run() 写一个死循环。不使用事件循环,运行线程。让线程将数据通过发送信号发送给GUI线程。

你可能感兴趣的:(QT)