如何在不阻塞主事件循环的情况下访问在主事件循环中创建的 QObject?



在我的场景中,我有一个复杂的 QObject* 和 QQuickItem* 层次结构,其中包含许多对应用程序都至关重要的子对象。

我希望完成的是:

从特定的 QObject 固有类型执行复杂的 CPU 密集型操作。此操作必须访问层次结构中许多不同 QObject 的属性,并且需要由单独的线程复制和分析大量内存(以至于简单地阻塞主事件循环比复制所有内容更有效(。

有没有办法直接访问作为创建新线程的主 QObject 的子级的 QObjects?

让我用一些代码澄清一下:

此代码段负责在符合某些条件的块网格中查找相邻块(这是我的 cpu 密集型操作,因为它需要在短时间内多次执行(

QList<QQuickItem *> Blockgrid::find_neighbors(QQuickItem *startItem, QList<QQuickItem *> currentNeighbors, QQuickItem *currentItem)
{
QList<QQuickItem*> neighbors;
QList<QQuickItem*> new_neighbors;
Blockrow* startRow = this->get_item_row(startItem);
int startCell = startRow->get_cell_number(startItem);
int startColor = startItem->property("blockColor").toInt();
Blockrow* currentRow = this->get_item_row(currentItem);
int currentCell = currentRow->get_cell_number(currentItem);
QList<QQuickItem*> potential_neighbors;
QQuickItem* topNeighbor = this->find_block(currentRow->rowNumber() - 1, currentCell);
QQuickItem* bottomNeighbor = this->find_block(currentRow->rowNumber() + 1, currentCell);
QQuickItem* leftNeighbor = this->find_block(currentRow->rowNumber(), currentCell - 1);
QQuickItem* rightNeighbor = this->find_block(currentRow->rowNumber(), currentCell + 1);
if (topNeighbor != nullptr) {
potential_neighbors << topNeighbor;
}
if (bottomNeighbor != nullptr) {
potential_neighbors << bottomNeighbor;
}
if (leftNeighbor != nullptr) {
potential_neighbors << leftNeighbor;
}
if (rightNeighbor != nullptr) {
potential_neighbors << rightNeighbor;
}
foreach (QQuickItem* potentialItem, potential_neighbors) {
if (potentialItem->property("blockColor") == startColor) {
if (potentialItem != currentItem) {
if (!neighbors.contains(potentialItem)) {
new_neighbors << potentialItem;

}
}
}
}
QList<QQuickItem*> final_neighbors;

if (new_neighbors.count() > 0) {
final_neighbors << currentNeighbors;
foreach (QQuickItem* neighborItem, new_neighbors) {
if (!final_neighbors.contains(neighborItem)) {
QList<QQuickItem*> send_neighbors;
send_neighbors << currentNeighbors << neighborItem << this->find_neighbors(startItem, send_neighbors, neighborItem);
foreach (QQuickItem* sendItem, send_neighbors) {
if (!final_neighbors.contains(sendItem)) {
final_neighbors << sendItem;
}
}
}
}
}
return final_neighbors;
}

重要的不是 CPU 密集型代码,它只是为了提供有关操作复杂性的一些上下文。

我试图完成的是在一个单独的线程中运行方法detect_matches


class Worker : public QObject
{
Q_OBJECT
public slots:
void detect_matches(Blockgrid* i_grid)
{
for (int row=0; row<i_grid->numberOfRows; row++) {
for (int col=0; col<i_grid->numberOfRows; col++) {
i_grid->find_block(row, col)->setProperty("opacity", 1.0);
}
}
for (int row=0; row<i_grid->numberOfRows; row++) {
for (int col=0; col<i_grid->numberOfRows; col++) {
QList<QQuickItem*> currentNeighbors;
QList<QQuickItem*> matches;
matches <<  i_grid->find_neighbors(i_grid->find_block(row,       col), currentNeighbors, i_grid->find_block(row, col));
if (matches.count() >= 3) {
foreach (QQuickItem* matchItem, matches) {
matchItem->setProperty("launched", true);
i_grid->find_block(row, col)->setProperty("launched",true);

}
}
}
}
}
}

};

此线程使用moveTothread技术启动:


void Blockgrid::find_matches() {
Worker *worker = new Worker;
worker->moveToThread(&workerThread);
worker->detect_matches(this);
}

有没有办法做到这一点?目前,一旦工作线程移动到单独的线程,它就无法与驻留在 Blockgrid 对象中的对象进行交互。

就像我之前说的,将所有数据从 Blockgrid 类复制到 Worker 线程本质上需要更多的 CPU 和处理时间,而不是线程完成计算所需的时间,这就是为什么我希望找到一种允许跨线程访问对象的技术。

谢谢。

你可以用父级构造你的QObject,然后访问主QObject的子项。从 QObject 继承的每个类都应该实现一个采用父 QObject* 的构造函数。

QObject *main = new QObject();
QObject *child1 = new QObject(main);
QObject *child2 = new QObject(main);

如果你把main放在可以访问它的地方,你可以迭代它的子级。

https://doc.qt.io/qt-5/qobject.html#children

foreach (QObject *child : main->children()) {
// do your stuff with each child
foreach (QObject *grandChild : main->children()) {
// do your stuff with each grandchild            
}
}

Worker 类的构造函数应采用指向共享对象的指针;然后 Worker 类应使用此注入的共享对象执行活动。

通过这种方式,您可以控制哪个工作线程将使用哪个共享对象。此外,需要通过互斥锁进行数据同步。

最新更新