简体   繁体   English

有人如何在不阻塞主事件循环的情况下从不同的线程访问在主事件循环中创建的 QObject?

[英]How can someone access a QObject created in the main event loop from a different thread without blocking the main event loop?

In my scenario, I have a complicated QObject* and QQuickItem* hierarchy set up with many child objects which are all critical to the application.在我的场景中,我有一个复杂的 QObject* 和 QQuickItem* 层次结构,其中包含许多对应用程序都至关重要的子对象。

What I wish to accomplish is:我希望完成的是:

Perform a complex, cpu-intensive operation from a specific QObject-inhereted type.从特定的 QObject 继承类型执行复杂的 CPU 密集型操作。 This operation must access properties from many of the different QObjects in the hierarchy and would require a large amount of memory being copied and parsed by the separate thread (to the point where it is more efficient to simply block the main event loop than to copy everything over).此操作必须访问层次结构中许多不同 QObject 的属性,并且需要由单独的线程复制和解析大量 memory(到了简单地阻塞主事件循环比复制所有内容更有效的地步)超过)。

Is there a way to directly access the QObjects that are children of the main QObject which creates a new thread?有没有办法直接访问作为创建新线程的主 QObject 的子级的 QObject?

Let me clarify a little bit with some code:让我用一些代码澄清一下:

This snippet is responsible for finding the neighboring blocks in a grid of blocks that match certain conditions (it is my cpu intensive operation because it needs to be performed many times in a short timespan)此代码段负责在匹配某些条件的块网格中查找相邻块(这是我的 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;
}

What is important is not the CPU intensive code, which is merely there to provide some context as to the complexity of the operation.重要的不是 CPU 密集型代码,它只是提供一些关于操作复杂性的上下文。

What I am trying to accomplish is running the method detect_matches in a separate thread:我想要完成的是在单独的线程中运行方法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);


                      }

                  }

              }
          }

      }

   }


};

This thread is started using the moveTothread technique:该线程使用moveTothread技术启动:


 void Blockgrid::find_matches() {

      Worker *worker = new Worker;
      worker->moveToThread(&workerThread);

      worker->detect_matches(this);

 }

Is there a way to make this work?有没有办法使这项工作? Currently the Worker thread cannot interact with the objects that live in the Blockgrid object once it has been moved to a separate thread..目前,一旦将 Worker 线程移至单独的线程,它就无法与 Blockgrid object 中的对象进行交互。

Like I said before, copying all of the data from the Blockgrid class into the Worker thread would essentially require more CPU and processing time than the time that the thread would take to finish computation, which is why I wish to find a technique that will allow for accessing objects across threads.就像我之前说的,将 Blockgrid class 中的所有数据复制到 Worker 线程中,实际上需要的 CPU 和处理时间比线程完成计算所需的时间要多,这就是为什么我希望找到一种允许用于跨线程访问对象。

Thanks.谢谢。

You could construct your QObject's with a parent, then access the children of the main QObject.您可以使用父级构造 QObject,然后访问主 QObject 的子级。 Every class that inherits from QObject should implement a constructor that takes a parent QObject*.每个从 QObject 继承的 class 都应该实现一个接受父 QObject* 的构造函数。

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

If you keep main somewhere you can access it, you can just iterate over its children.如果您将 main 保留在可以访问它的地方,则可以迭代其子项。

https://doc.qt.io/qt-5/qobject.html#children 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            
    }
}

The constructor of your Worker class should take a pointer to the shared object;您的 Worker class 的构造函数应该采用指向共享 object 的指针; and then the Worker class should perform activities with this injected shared object.然后 Worker class 应该使用这个注入的共享 object 执行活动。

In this way you can control which Worker thread will use which shared object.通过这种方式,您可以控制哪个 Worker 线程将使用哪个共享 object。 Also, need to take care of data sync via mutex.此外,需要通过互斥锁处理数据同步。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Qt:立即启动线程,不延迟主事件循环 - Qt: Immediately start thread, without delay of main event loop 如何在Qt的主事件循环中使用std :: thread? - How to use std::thread with Qt's main event loop? 在主事件循环之前如何创建一些对象? - How some objects are created before main event loop? 本地QEventLoop-等待线程发出的信号-阻止处理来自主事件循环的事件 - Local QEventLoop - waiting for a signal from thread - prevent processing events from main event loop 关于QThread,QObject,线程亲和力和事件循环的困惑 - Confusion regarding QThread, QObject, Thread Affinity and Event Loop 从非Qt线程或ouside Qt主事件循环发出Qt信号,为4.5 - emit Qt signal from non Qt Thread or ouside Qt main event loop with at 4.5 如何在循环中运行 qt 主 window 避免 Qt app.exec() 阻塞主线程 - how to run qt main window in loop avoid Qt app.exec() blocking main thread 在Qt中,当事件循环的线程拥有的QObject上的一个槽正在执行时,QThread的事件循环是否阻塞? - In Qt, does a QThread's event loop block while a slot on a QObject owned by the event loop's thread is executing? 在主 Qt 事件循环中执行冗长的阻塞操作时可靠地显示“请稍候”对话框 - Reliably showing a "please wait" dialog while doing a lengthy blocking operation in the main Qt event loop PyQt5:如何将QObject移动到主线程? - PyQt5: How to move a QObject to the main thread?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM