阅读量:0
文章目录
需求
调用第三方库的一个耗时函数,需要等待返回结果进行下一步,但是又不想阻塞Qt界面。
解决思路
创建子线程等待主线程调用,在主线程使用QEventLoop循环等待子线程返回执行结果,子线程内使用QWaitCondition,主要用于多线程编程,它提供了一种机制来同步线程间的操作,通过调用wakeOne()或wakeAll()方法唤醒等待的线程。
子线程
子线程继承QThread类,在run函数内执行任务,执行完后发送信号给主线程。
示例如下:
子线程头文件:
// 子线程 防止阻塞主进程 #pragma once #include <QThread> #include <QMutex> #include <QWaitCondition> #include <QDebug> class QThreadControl : public QThread { Q_OBJECT public: QThreadControl(QObject* parent = nullptr); ~QThreadControl(); // 子线程执行函数 void run() override; // 结束子线程 void stop(); // 等待返回数据 QByteArray result(); signals: // 子线程执行完任务通知主线程 void taskFinished(QByteArray); public: // 发送数据并等待返回值的函数 void sendSerialCommand(const QByteArray& command, CAMERA _current_camera); // 设置相关参数 void setParameter(const QByteArray& command, CAMERA _current_camera); bool m_active; // 保持线程活跃标志位 自定义类对象 current_item_; // 当前对象 QByteArray command_; // 控制指令 QByteArray result_; // 返回信息 mutable QMutex m_mutex; // 多线程加锁 // 唤醒等待的线程 与互斥锁(QMutex)一起使用 以保护共享数据并同步线程 QWaitCondition m_condition; };
子线程源文件:
#include "QThreadControl.h" #include<Windows.h> QThreadControl::QThreadControl(QObject* parent) { m_active = true; } QThreadControl::~CameraCtrolLens() { stop(); wait(); } void QThreadControl::run() { while (m_active) { QMutexLocker locker(&m_mutex); m_condition.wait(&m_mutex); if (!m_active) break; // 执行任务 sendSerialCommand(command_, current_item_); // 任务完成后发送信号回主线程 emit taskFinished(result_); } } void QThreadControl::stop() { m_active = false; m_condition.wakeOne(); } QByteArray QThreadControl::result() { QMutexLocker locker(&m_mutex); m_condition.wait(&m_mutex, 5000); // 等待最多5秒 return result_; } void QThreadControl::sendSerialCommand(const QByteArray& command,CAMERA _current_camera) { QByteArray revice_data(16, char(0)); if (_current_camera != nullptr) { int rev_num = 0; bool is_reviced = false; while (!is_reviced) { if (revice_data.data() == QByteArray("waiting\r\n") || revice_data.data() == QByteArray("")) { Sleep(100); //qDebug() << "send lens command waiting..."; ++rev_num; } else { is_reviced = true; break; } if (rev_num >= 80) { revice_data.append("ERROR"); break; } } } else { revice_data.append("ERROR"); } result_ = revice_data; } void QThreadControl::setParameter(const QByteArray& command, 自定义类对象 _current_item) { QMutexLocker locker(&m_mutex); current_camera_ = _current_camera; command_ = command; m_condition.wakeOne(); }
主线程
主线程调用如下所示,先设置参数,后创建loop循环,该循环会一直等待子线程任务结束退出,保证了返回值的数据同步,同时不会阻塞主界面操作。需要注意的是,主线程冲突按钮需要设置为不可用状态。
QByteArray test; test.append(_send_order); camera_ctrol_lens_->setParameter(test,current_camera_); // 创建事件循环对象 为了阻塞该函数等待结果返回 QEventLoop loop; // 主循环,这里我们不需要循环,因为只需要执行一次任务 QObject::connect(camera_ctrol_lens_, &CameraCtrolLens::taskFinished, &loop, &QEventLoop::quit); // 进入事件循环,等待线程完成 loop.exec(); // 获取结果 return rev_value_;