Qt中线程的学习记录
Qt线程方式:
示例:pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。
都有类似的功能集
Qt提供线程池
基本经验法则
QObject::connect()
QCoreApplication::postEvent()
signal
QPixmap
QObject
子类,所UI相关的除外 如QWidget
和QQuickItems
QSvgGenerator
QSvgRenderer
QTextDocument
,甚至包括它的clone()函数继承QTread 和movetothread这两种线程的方式,太常见了,网络上资料也多的很,这里就不详细描述,看官方文档或者网络上一查即可:
Qt 文档中案例:
class WorkerThread : public QThread
{
Q_OBJECT
void run() override {
QString result;
/* ... here is the expensive or blocking operation ... */
emit resultReady(result);
}
signals:
void resultReady(const QString &s);
};
void MyObject::startWorkInAThread()
{
WorkerThread *workerThread = new WorkerThread(this);
connect(workerThread, &WorkerThread::resultReady, this, &MyObject::handleResults);
connect(workerThread, &WorkerThread::finished, workerThread, &QObject::deleteLater);
workerThread->start();
}
Qt 文档中案例:
class Worker : public QObject
{
Q_OBJECT
public slots:
void doWork(const QString ¶meter) {
QString result;
/* ... here is the expensive or blocking operation ... */
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, &QThread::finished, worker, &QObject::deleteLater);
connect(this, &Controller::operate, worker, &Worker::doWork);
connect(worker, &Worker::resultReady, this, &Controller::handleResults);
workerThread.start();
}
~Controller() {
workerThread.quit();
workerThread.wait();
}
public slots:
void handleResults(const QString &);
signals:
void operate(const QString &);
};
使用方式也很简单,类似QTthread的run
class HelloWorldTask : public QRunnable
{
void run() override
{
qDebug() << "Hello world from thread" << QThread::currentThread();
}
};
HelloWorldTask *hello = new HelloWorldTask();
// QThreadPool takes ownership and deletes 'hello' automatically
QThreadPool::globalInstance()->start(hello);
Qt 的高级线程,使用起来更简单,有点你std::thread
int myFunc0()
{
while(1){...}
}
int myFunc1(int param1,const QString& param2)
{
while(1){...}
}
class MyClass{
public:
int myFunc2(int param1,const QString& param2)
{
while(1){...}
}
}
void test()
{
/// 普通函数用法,不带参
QFuture<int> result = QtConcurrent::run(myFunc1);
int p1 = 10;QString p2 = "hello";
/// 普通函数用法,带参
QFuture<int> result = QtConcurrent::run(myFunc1,p1,p2);
MyClass cl;
/// 类成员函数
QFuture<int> result = QtConcurrent::run(&cl,&MyClass::myFunc2,p1,p2);
//lambda表达式
QFuture<int> result = QtConcurrent::run([=](){
while(1){...}
});
}
QFuture 是一个异步计算的结果
+ 横版类,没见有继承QObject
+ 使用pause()和resume()函数支持暂停和恢复功能(仅当任务仍在队列中时)
+ 提供了进度信息
+ 其它有用的函数(isFinished, isRunning, isStarted, waitForFinished)
+ 利用线程池中的空闲线程
利用QFutureWatcher
可以实现线程的监听
各方案比较
特征 | QThread | QRunnable and QThreadPool | QtConcurrent::run() | Qt Concurrent (Map, Filter, Reduce) | WorkerScript |
---|---|---|---|---|---|
语言 | c++ | c++ | c++ | c++ | qml |
可以指定线程优先级 | 是 | 是 | |||
线程内可以事件循环 | 是 | ||||
线程内可以通过信号接收数据更新 | 是 | 是 | |||
线程可以通过信号控制 | 是 | 是 | |||
线程可以通过QFuture监听 | 是 | ||||
内置暂停/恢复/取消功能 | 是 |
QThread生命周期 | 操作 | 方案 |
---|---|---|
一次调用 | 从线程内发送线程更新状态 | Qt提供了不同的解决方案: 1. QThread::run()的重新实现并启动,通过发信号以更新进度 2. 重新实现QRunnable::run(),使用QThreadPool进行启动,写入线程安全变量以更新进度. 3. 使用QtConcurrent::Run()运行该函数,写入线程安全变量以更新进度 |
一次调用 | 从线程内发送线程更新状态并获取返回值 | 使用 QtConcurrent: : Run ()运行该函数。让 QFutureWatcher 在函数返回时发出完成()信号,并调用 QFutureWatcher: : result ()来获取函数的返回值。 |
一次调用 | 使用所有可用的核心对容器的所有项执行操作。例如,从图像列表生成缩略图。 | 使用 Qt Concurrent 的 QtConcurrent: : filter ()函数选择容器元素,使用 QtConcurrent: : map ()函数对每个元素应用操作。要将输出折叠成单个结果,可以使用 QtConcurrent: : filteredReduced()和 QtConcurrent: : mappedReduced()代替。 |
一次调用/持久的 | 在纯 QML 应用程序中进行长时间的计算,并在结果准备就绪时更新 GUI | 将计算代码放在一个脚本中,并将其附加到一个 WorkScript 实例。调用 WorkerScript.sendMessage ()在新线程中启动计算。让脚本也调用 sendMessage () ,将结果传递回 GUI 线程。在那里处理结果并更新 GUI |
持久的 | 让一个对象生活在另一个线程中,该线程可以根据请求执行不同的任务和/或接收要处理的新数据 | 子类化一个 QObject 来创建一个 worker。实例化这个 worker 对象和一个 QThread。将工作线程移动到新线程。通过排队的信号槽连接向辅助对象发送命令或数据 |
持久的 | 在另一个线程中重复执行代价高昂的操作,其中该线程不需要接收任何信号或事件 | 直接在 QThread: : run ()的重新实现中编写无限循环。不使用事件循环启动线程。让线程发出信号将数据发送回 GUI 线程 |
https://doc.qt.io/qt-5/threads-technologies.html
Qt官方有提到,我这里只是翻译了一下
QMetaObject
,可以从线程内发出QCoreApplication::postEvent()
发送事件QWaitCondition
加上互斥锁保护的线程全局数据lock(),unlock()
tryLock()
tryLock(int timeout)
QMutexLocket
如: QMutexLocker locker(&m_mutex);
它的生命周期结束即释放锁,同 std::lock_guard
QReadWriteLock
: 与QMutex
相比,增加了并发性,允许多次读取QWaitCondition
:QSemaphore
,QSystemSemaphore
: 保护多个相同的资源const QSemaphoreReleaser releaser(semaphore);
QWaitCondition::wait()
让线程等待某个事件QMutex
(而不是QReadWriteLock)
,才能从锁定状态进入等待状态QWaitCondition::wakeOne()
随机唤醒一个等待条件的线程,或者使用 QWaitCondition::wakeAll()
唤醒所有等待的线程提供了代码示例,有需要的可以去看看
https://github.com/tianxiaofan/QtMultiThread