4

我知道我们不能在非 GUI 线程(QThread)中使用 GUI 交互。但我不知道我们是否可以或不能与QAbstractItemModel线程中的模型()进行交互,如果为真,那么如何以正确的方式进行交互?

老实说,我在谷歌和 SO 上搜索了一些关于这个的东西,似乎我的问题没有相关的答案。

4

1 回答 1

3

“与模型交互”是什么意思?如果您的意思是要通过直接操作从多个线程访问模型,那么您必须序列化对模型的访问。由于模型中有很多方法,我建议您不要在模型中添加互斥锁——这会非常乏味且容易出错,因为很容易忘记互斥锁储物柜。相反,使用您的模型继承 QObject 的事实,因此可以接受事件。

  1. 您的 gui 线程直接访问模型。
  2. 其他线程通过向模型发布事件(并且可能接收回复事件)与模型交互。
  3. gui 线程将使用任何其他访问顺序处理这些事件,从而保护您的模型免受并发访问。

其他线程当然可以接收来自模型的回复——也可以通过事件。您将有两个事件基类:一个Request用于从模型请求事物的类,然后是一个Response模型将用于回复的事件基类。Request 类应该有一个QObject* sender成员,以便模型知道要将回复事件发布到哪个 QObject。您可能希望请求和回复都带有相同的标识符(例如连续递增的 int),以便可以匹配请求和响应。

QThread::run()您必须通过事件而不是通过重新实现,而是在 QObject 中实现与模型交互的所有线程代码。实例化 后QObject,只需将其移至单独的线程即可。run()如果有任何事件、信号或计时器准备好,QThread 的默认实现将旋转一个事件循环以保持您的 QObject 执行。零持续时间计时器是一种保持线程永久忙碌的方法,但请确保不要一次性进行太多处理,否则会延迟传入事件的处理。

也可以使用信号和槽,但不能直接调用,只能:

  1. connect()给他们,
  2. QMetaObject::invokeMethod通过with调用它们Qt::QueuedConnection
  3. 通过在主线程上下文中执行的仿函数(比如 lambda)调用它们;请参阅此答案以了解如何执行此操作。

在幕后,当您将信号连接到位于不同线程中的 QObject 的插槽时,Qt 会创建一个连接,将每个信号编组为 a QMetaCallEvent,然后在具有目标插槽的 QObject 所在的线程中将其解组。

于 2012-05-29T02:01:13.907 回答