在Qt信号/槽的上下文中使用观察者模式

Using observer pattern in the context of Qt signals/slots

本文关键字:观察者模式 上下文 Qt 信号      更新时间:2023-10-16

我正试图为我正在研究的算法做出一些设计决策。我想我想使用信号和插槽来实现观察者模式,但我不确定一些事情。

这是我正在研究的算法:

1.) Load tiles of an image from a large file
1a.) Copy the entire file to a new location
2.) Process the tiles as they are loaded
3.) If the copy has been created, copy the resulting data into the new file

所以我设想有一个类的函数,比如loadAllTiles(),它会发出信号告诉processTile(),另一个tile已经准备好被处理,同时继续加载下一个tile。

processTile()将执行一些计算,完成后,向writeResults()发出信号,表示准备写入一组新的结果数据。writeResults()将验证复制是否完成,并开始写入输出数据。

这听起来合理吗?是否有一种方法,使loadAllTiles()加载在一个瓷砖,传递该数据以某种方式processTile(),然后继续加载下一个瓷砖?我在考虑是否可以建立一个列表来存储准备处理的磁贴,以及另一个列表来存储准备写入磁盘的结果磁贴。我想缺点是我必须以某种方式保持这些列表的完整性,这样多个线程就不会试图从列表中添加/删除项目。

你的问题不完全清楚,但似乎你想把工作分成几个线程,这样瓷砖的处理可以在你完成加载整个集之前开始。

考虑一个多线程处理管道架构。为每个任务分配一个线程(加载、复制、处理),并通过Producer-Consumer队列(又名BlockingQueue)在任务之间传递tile。更精确地说,将指针(或共享指针)传递给tile,以避免不必要的复制。 在Qt中似乎没有现成的线程安全的BlockingQueue类,但您可以使用QQueue, QWaitConditionQMutex来卷起自己的。以下是一些灵感来源:
  • Just Software Solutions的博客文章
  • Java的BlockingQueue
  • ZThreads的BlockingQueue

虽然Qt内没有现成的BlockingQueue,但似乎使用信号&带有Qt::QueuedConnection选项的槽可以达到相同的目的。这篇Qt博客文章就是这样使用信号和槽的。

您可能希望将这种管道方法与内存池空闲列表相结合,以便已经分配的瓷砖在您的管道中回收。

这是管道的概念草图:

TilePool -> TileLoader -> PCQ -> TileProcessor -> PCQ -> TileSaver -
  ^                                                                 |
   ----------------------------------------------------------------/

其中PCQ表示一个生产者-消费者队列。

为了利用更多的并行性,您可以尝试在每个阶段使用线程池。

你也可以考虑看看英特尔的线程构建块。我自己没试过。请注意开源版本的GPL许可。

任何类型的并行化锁机制都可以防止列表损坏,无论是简单的锁,信号量等等。

否则,这种方法听起来是合理的,即使我要说文件必须是大的才有意义。只要它们能轻松地装入内存,我不认为分段加载它们有什么意义。另外:你打算如何在不读取整个图像重复提取瓷砖?