在 QAbstractTableModel 中使用多个线程之间共享的数据

using data shared between multiple threads in a QAbstractTableModel

我有一个使用 Q_GLOBAL_STATIC 实现的单例 class,它包含一个必须从多个线程访问的数据结构,我在 class 中实现了访问器函数,它会锁定访问数据之前的互斥体,以便所有对共享数据的访问都被序列化。

问题是我想在 QAbstractTableModel 中使用这些数据,我可以简单地使用我实现的访问器函数,并一次从我覆盖的 data()columnCount()rowCount()。但我认为这是不够的,因为在对 data() 的两次后续调用之间,另一个线程可能会跳入并更改项目的数量,例如 (rowCount()),并且模型的线程可能最终会越界访问数据.

我想我需要在模型重置的第一次调用 columnCount()rowCount() 之前锁定互斥锁,并且只有在所有数据都读入模型时(在最后一次调用 data()),有办法吗?还是我想错了?

我想在模型重置时将共享数据结构复制到本地数据结构(并且只在复制操作时锁定互斥锁),然后安全地访问复制的数据,但这不是有点矫枉过正吗?没有更有效的解决方案吗?

在Qt的Model-View框架中,QAbstractItemModel和QAbstractItemView之间的接口根本不是线程安全的,它被设计成只能与一个线程一起使用,这个线程必须是GUI线程,即主线程,因为视图在 GUI 上绘画,这不能在主 (GUI) 线程之外的另一个线程中安全地完成。

因此,模型必须拥有自己的数据并将其与真实数据同步。如果您的数据集很大,您可以依靠 fetchMore() 来避免在每个模型实例中复制整个数据。看看 QtSql's sql models code 中做了什么。那么你提出的lock-between-calls问题就比较容易解决

如果真实的数据持有者对象能够发出连接到模型实例的信号,您甚至可以以 event-driven 的方式更新模型。由于 auto/queued 信号连接,模型插槽将在主 (GUI) 线程中执行,因此不需要使用 QAbstractItemModel-QAbstractItemView 接口是线程安全的。