Qt|实现数据同步又不阻塞主界面

文章目录

需求

调用第三方库的一个耗时函数,需要等待返回结果进行下一步,但是又不想阻塞Qt界面。

解决思路

创建子线程等待主线程调用,在主线程使用QEventLoop循环等待子线程返回执行结果,子线程内使用QWaitCondition,主要用于多线程编程,它提供了一种机制来同步线程间的操作,通过调用wakeOne()或wakeAll()方法唤醒等待的线程。

子线程

子线程继承QThread类,在run函数内执行任务,执行完后发送信号给主线程。

示例如下:

子线程头文件:

cpp 复制代码
// 子线程 防止阻塞主进程
#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; 
};

子线程源文件:

cpp 复制代码
#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循环,该循环会一直等待子线程任务结束退出,保证了返回值的数据同步,同时不会阻塞主界面操作。需要注意的是,主线程冲突按钮需要设置为不可用状态。

cpp 复制代码
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_;
相关推荐
肥or胖13 小时前
【FFmpeg 快速入门】本地播放器 项目
开发语言·qt·ffmpeg·音视频
小灰灰搞电子19 小时前
Qt Quick 粒子系统详解
开发语言·qt
暴躁茹21 小时前
Qt 将触摸事件转换为鼠标事件(Qt4和Qt5及以上版本)
开发语言·qt·计算机外设
大专生学编程1 天前
QT简介和QT环境搭建
c++·qt
feiyangqingyun1 天前
Qt/C++开发监控GB28181系统/视频点播没有ssrc问题的处理/兼容各种设备和应用场景需求
c++·qt·gb28181
小堃学编程1 天前
QT跨平台应用程序开发框架(10)—— Qt窗口
开发语言·qt
轩宇^_^1 天前
Qt CMake 学习文档
数据库·qt·学习
小徐不徐说1 天前
QT技巧之快速搭建串口收发平台
开发语言·c++·qt·串口·软件构建·个人开发·通信
天堂陌客1 天前
QT 交叉编译环境下,嵌入式设备显示字体大小和QT Creator 桌面显示不一致问题解决
开发语言·qt·字库
小堃学编程2 天前
QT跨平台应用程序开发框架(9)—— 容器类控件
开发语言·qt