gpt4 book ai didi

c++ - 在 Qt 信号中发射 QVector 引用导致复制

转载 作者:搜寻专家 更新时间:2023-10-31 01:47:31 24 4
gpt4 key购买 nike

我正在努力构建一个与线扫描相机对话的应用程序。最终,我想传递一个 384x128 unsigned short 的“ block ”(即数组)。 QThread 每 100 毫秒计算一次值(数据采集)到 QRunnable (数据处理)。这意味着 QRunnable在下一个 block 到达之前将有 100ms 来处理数据。

我仍然不确定移动数据的正确方法。现在,我正在使用 QVector。在 Qt4 中,我理解隐式共享意味着如果在信号中发出 QVector 则不会被复制,直到对象被写入。但是,在我制作的一个小型测试应用程序中,我不确定我是否理解这到底意味着什么。这是下面提供的 MWE 的输出...

Acquire thread: init.
Acquire thread: block acquired: 0x106485e78 Content: {1, 2, 3, 4}
GUI thread: received signal: 0x7fff5fbfda98 Content: {1, 2, 3, 4}
Acquire thread: block acquired: 0x106485e78 Content: {1, 2, 3, 4}
GUI thread: received signal: 0x7fff5fbfda98 Content: {1, 2, 3, 4}
Acquire thread: block acquired: 0x106485e78 Content: {1, 2, 3, 4}
GUI thread: received signal: 0x7fff5fbfda98 Content: {1, 2, 3, 4}

我正在使用具有四个值的“虚拟”QVector,并在线程运行时跟踪 vector 的地址。数据自始至终都是正确的,但似乎复制了一份。我不会在应用程序中的任何时候更改数据...只是显示。我试过使用 const QVector<unsigned short>自始至终,使用引用等的各种迭代。地址总是在变化。由于性能在这里很重要,所以我担心在 384*128 值时制作 QVector 的拷贝。

此外,在另一个 SO 问题中,我正在努力弄清楚如何让 QRunnable 接收数据(这一切都被排除在这个例子之外)。但是,这里要注意这一点很重要,因为我的想法是让 QRunnable 在对 image_buffer引用 上运行。存在于 QThread 中。我只是不知道该怎么做。

具体问题:

-- 为什么看起来是复制的?这是因为多线程吗?

-- 我是否必须在整个过程中明确使用引用(即 image_buffer&),从而完全删除 QVector?或者,我应该担心拷贝吗?

-- 对于我的情况,将数据从 QThread 传递到 QRunnable 的正确方法是什么?

MWE 下面来演示不同的地址。免责声明:我正在学习 C++。没有经过正规的培训,只有眼前的几本好书。

main.cpp

#include <QApplication>
#include <QMetaType>
#include <QVector>

#include "appwidget.h"

int main(int argc, char* argv[]) {

QApplication app(argc, argv);

AppWidget gui;
gui.show();

qRegisterMetaType<QVector<unsigned short> >("QVector<unsigned short>");

return app.exec();
}

** appwidget.h **

#ifndef APPWIDGET_H
#define APPWIDGET_H

#include <QWidget>
#include <QVector>

#include "acquire.h"

class AppWidget : public QWidget
{ Q_OBJECT

public:
AppWidget(QWidget *parent = 0);

protected:
Acquire thread;

public slots:
void processBlock(QVector<unsigned short>);

};

#endif

appwidget.cpp

#include <QtGui>
#include <iostream>

#include "appwidget.h"

AppWidget::AppWidget(QWidget *parent)
: QWidget(parent)
{

thread.liftoff();
connect(&thread, SIGNAL(blockAcquired(QVector<unsigned short>)), this, SLOT(processBlock(QVector<unsigned short>)));

setWindowTitle(tr("TestApp"));
resize(550, 400);

}

void AppWidget::processBlock(QVector<unsigned short> display_buffer)
{
std::cout << "GUI thread: received signal: "
<< &display_buffer
<< " Content: {"
<< display_buffer.at(0) << ", "
<< display_buffer.at(1) << ", "
<< display_buffer.at(2) << ", "
<< display_buffer.at(3)
<< "}" << std::endl;

}

获取.h

#ifndef ACQUIRE_H
#define ACQUIRE_H

#include <QVector>
#include <QThread>

class Acquire : public QThread {

Q_OBJECT

public:
Acquire(QObject *parent = 0);
~Acquire();
QVector<unsigned short> display_buffer;

void liftoff();

signals:
void blockAcquired(QVector<unsigned short>);

protected:
void run();

private:

};

#endif

获取.cpp

#include <iostream>
#include <time.h>
#include <stdlib.h>

#include "acquire.h"

Acquire::Acquire(QObject *parent)
: QThread(parent)
{
}

Acquire::~Acquire()
{
std::cout << "Acquire thread: dying." << std::endl;
wait();
}

void Acquire::liftoff()
{
std::cout << "Acquire thread: init." << std::endl;
start();
}

void Acquire::run()
{
QVector<unsigned short> display_buffer(2 * 2);

forever {

/*
display_buffer will ultimate be a memcpy of image_buffer
.. image_buffer updated continuously, 1 line every 800000ns x 128 lines
*/

display_buffer[0] = 1;
display_buffer[1] = 2;
display_buffer[2] = 3;
display_buffer[3] = 4;
nanosleep((struct timespec[]){{0, 800000*128}}, NULL);

std::cout << "Acquire thread: block acquired: "
<< &display_buffer
<< " Content: {"
<< display_buffer.at(0) << ", "
<< display_buffer.at(1) << ", "
<< display_buffer.at(2) << ", "
<< display_buffer.at(3)
<< "}" << std::endl;

emit blockAcquired(display_buffer);

}
}

最佳答案

在这种情况下会进行复制,因为您是按值传递的,而且跨线程边界的信号是排队的。不过这很好,因为 implicit-sharing表示它们是浅拷贝。如果原始文件和拷贝都仅用于读取,则复制几乎没有开销。

不幸的是,在您的程序中实际上并非如此。当它在信号发射后循环回来时,你的永远循环将修改 vector 。在此示例中,它实际上不会更改 vector 中的任何内容,因为您始终只是分配 1、2、3、4,但调用非常量运算符 [] 足以触发深层复制。

我的结论是:您可以同步并在您的读者和作者之间共享相同的缓冲区,或者您可以异步并将您的写缓冲区的拷贝提供给您的读者。您不能异步并在读者和作者之间共享相同的缓冲区。

您处理此问题的方式似乎适合异步处理。根据您的数据生成和数据处理的特点,您可能(也可能不会)找到更好的同步解决方案。使异步代码同步的最简单方法是将连接类型提供为 Qt::BlockingQueuedConnectionconnect .

关于c++ - 在 Qt 信号中发射 QVector 引用导致复制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19120829/

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