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_;
相关推荐
锦亦之22336 小时前
QT+OSG+OSG-earth如何在窗口显示一个地球
开发语言·qt
柳鲲鹏9 小时前
编译成功!QT/6.7.2/Creator编译Windows64 MySQL驱动(MinGW版)
开发语言·qt·mysql
三玖诶9 小时前
如何在 Qt 的 QListWidget 中逐行添加和显示数据
开发语言·qt
阳光开朗_大男孩儿15 小时前
DBUS属性原理
linux·服务器·前端·数据库·qt
Alphapeople17 小时前
Qt Modbus
开发语言·qt
竹林海中敲代码17 小时前
Qt Creator 集成开发环境 常见问题
qt·qt工具常见问题
竹林海中敲代码20 小时前
Qt安卓开发连接手机调试(红米K60为例)
android·qt·智能手机
长沙红胖子Qt21 小时前
关于 Qt运行加载内存较大崩溃添加扩大运行内存 的解决方法
开发语言·qt·qt扩大运行内存
gopher951121 小时前
qt相关面试题
开发语言·qt·面试
三玖诶1 天前
在 Qt 中使用 QLabel 设置 GIF 动态背景
开发语言·qt·命令模式