gpt4 book ai didi

c++ - 返回指向在不同线程中更新的 QML 的 C++ 指针

转载 作者:太空狗 更新时间:2023-10-29 21:39:37 24 4
gpt4 key购买 nike

我是 Qt/QtQuick 的新手,我必须开发一个应用程序,它使用定期通过网络在不同线程中接收的一些传感器数据。该数据应该在c++内部用于计算,并且最新的数据也应该在QML中显示。通过使用互斥锁进行保护,所有内容都在 c++ 中设置为线程安全的,并且数据在 QML 中明显更新。但是,我对 QML 端的线程安全有一些担忧,我在网上找不到关于这个主题的信息或示例。具体来说,我关心的是返回一个指针(我猜这是将 C++ 对象返回给 QML 的唯一方法)而不是一个值,因此是一个对象的拷贝。这是一个证明问题的最小示例:

// File data.h
#include <QObject>

class Data : public QObject {
Q_OBJECT
Q_PROPERTY(QString someData READ someData WRITE setSomeData NOTIFY someDataChanged)

public:
explicit Data(QObject* parent = nullptr)
:QObject(parent)
{
}

QString someData() const {
return _someData;
}

void setSomeData(const QString& value) {
if (_someData != value) {
_someData = value;
emit someDataChanged();
}
}

signals:
void someDataChanged();

private:
QString _someData;

}; // Data


// File: controller.h
#include <QObject>

#include <thread>

class Controller : public QObject {
Q_OBJECT
Q_PROPERTY(Data data READ data NOTIFY dataChanged)

public:
explicit Controller(QObject* parent = nullptr)
:QObject(parent)
,_running(false)
,_data(nullptr)
{
_data = new Data();
}

virtual ~Controller() {
delete _data;
}

void start() {
_running = true;
_thread = std::thread([this]() { _threadFunc(); });
}

void stop() {
_running = false;

if (_thread.joinable()) {
_thread.join();
}
}

Data* data() {
return _data;
}

signals:
void dataChanged();

private:
void _threadFunc() {
while (_running) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
_data.setSomeData("foo");
emit dataChanged();
}
}

bool _running;
std::thread _thread;
Data* _data;

}; // Controller

// File main.qml
import QtQuick 2.0

Rectangle {
width: 100
height: 100

Text {
anchors.centerIn: parent
text: Controller.data.someData
}
}

Data 是一个简单的容器,包含一个 QString 作为属性。 Controller 包含属性数据并启动一个线程,该线程定期更新数据并将更改作为信号发出。输出将正确显示,但返回原始指针感觉很不安全。所以我的问题是:

  1. 如果数据写入速度过快并且线程在 QML 使用指针更新视觉对象的同时操作数据,会发生什么情况?
  2. 是否有返回原始指针的替代方法,例如,Qt 为此目的提供的东西和我还没有找到的东西?
  3. 在使用 Qt/QML 时,我的想法是错误的吗?我首先开发了 C++ 后端(没有任何 Qt 部分),现在我试图将它连接到 GUI。也许我应该从一开始就更好地围绕 Qt 或 QML 友好地设计后端?

最佳答案

好吧,我想我找到了解决问题的方法:我仍然确信在同一个对象上工作会导致问题。我阅读了一些关于 QML 所有权的内容,发现通过使用属性,所有权仍然在 C++ 端。通过使用返回指针的函数,QML 接管了所有权并稍后会注意删除该对象。因此,如果有一天有人遇到同样的问题,我在这里所做的就是:

// File data.h
#include <QObject>

class Data : public QObject {
Q_OBJECT
Q_PROPERTY(QString someData READ someData WRITE setSomeData NOTIFY someDataChanged)

public:
explicit Data(QObject* parent = nullptr)
:QObject(parent)
{
}

Data(const Data& data)
:QObject(data.parent)
,_someData(data.someData)
{
}

QString someData() const {
return _someData;
}

void setSomeData(const QString& value) {
if (_someData != value) {
_someData = value;
emit someDataChanged();
}
}

signals:
void someDataChanged();

private:
QString _someData;

}; // Data


// File: controller.h
#include <QObject>

#include <thread>
#include <mutex> // New

class Controller : public QObject {
Q_OBJECT
//Q_PROPERTY(Data data READ data NOTIFY dataChanged) // Removed

public:
explicit Controller(QObject* parent = nullptr)
:QObject(parent)
,_running(false)
,_data(nullptr)
{
_data = new Data();
}

virtual ~Controller() {
delete _data;
}

void start() {
_running = true;
_thread = std::thread([this]() { _threadFunc(); });
}

void stop() {
_running = false;

if (_thread.joinable()) {
_thread.join();
}
}

Q_INVOKABLE Data* data() { // Modified to be an invokable function instead of a property getter
std::lock_guard<std::mutex> lock(_mutex); // New
return new Data(*_data); // New
}

signals:
void dataChanged();

private:
void _threadFunc() {
while (_running) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));

std::lock_guard<std::mutex> lock(_mutex); // New
_data.setSomeData("foo");
emit dataChanged();
}
}

bool _running;
std::thread _thread;
std::mutex _mutex; // New
Data* _data;

}; // Controller

// File main.qml
// NOTE: Controller is registered as context property alias 'controller'
import QtQuick 2.0

// Import the datatype 'data' to be used in QML
//import ...

Rectangle {
id: myRect
width: 100
height: 100

property Data data

Connections {
target: controller
onDataChanged: {
myRect.data = controller.data()
}
}

Text {
anchors.centerIn: parent
text: data.someData
}
}

基本上,我会确保锁定对象并进行复制。然后 QML 可以安全地使用此拷贝,并且 QML 引擎将在使用后注意删除内存。此外,我在 QML 中创建了 Data 对象的一个​​实例,并注册了获取和分配最新拷贝的信号。

关于c++ - 返回指向在不同线程中更新的 QML 的 C++ 指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32423615/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com