C++ 将对象移动到其他线程

C++ 将对象移动到其他线程,c++,multithreading,qt,C++,Multithreading,Qt,我的应用程序使用自定义序列化机制 阶段1)该机制在单独的线程上加载数据集群,并在其中创建所有适当的对象,依此类推 阶段2)一旦它们全部反序列化,它将它们交给主应用程序线程,并在那里完成序列化,例如设置对象之间的连接等 这个机制是对我的框架的一个新的补充——在此之前,我正在反序列化主线程上的所有内容 我遇到的问题是,在反序列化过程中创建的一些对象是Qt对象(基本上是一堆小部件)。 它们都记录创建它们的线程的ID。当“第二阶段”到来时,这些对象开始抱怨它们都不属于这个线程,因此无法发送信号等等 所以

我的应用程序使用自定义序列化机制

阶段1)该机制在单独的线程上加载数据集群,并在其中创建所有适当的对象,依此类推

阶段2)一旦它们全部反序列化,它将它们交给主应用程序线程,并在那里完成序列化,例如设置对象之间的连接等

这个机制是对我的框架的一个新的补充——在此之前,我正在反序列化主线程上的所有内容

我遇到的问题是,在反序列化过程中创建的一些对象是Qt对象(基本上是一堆小部件)。 它们都记录创建它们的线程的ID。当“第二阶段”到来时,这些对象开始抱怨它们都不属于这个线程,因此无法发送信号等等

所以我在QObject上找到了一个名为“moveToThread”的方法。不过,这个小错误不是很有用,因为它执行检查并防止将对象从不同的线程移动到当前线程(为什么要破坏约束,我不知道)

有人知道我该怎么做吗?我可以保证这些对象只能在一个单独的线程上创建,从那时起,它们都将在主线程上运行

谢谢,
涉及多线程时,必须小心处理QoObject的PAKSA实例或QoObject子类的任何实例。 请参阅,以获取对该主题的介绍

假设应用程序包含两个线程AB。 假设线程A创建了一个对象QObject实例

实例被称为活在线程A中。这意味着: -它可以直接向线程A中的所有其他对象发送和接收信号。 -从线程A对myInstance方法的所有调用都是线程安全的

另一方面,从另一个线程B访问实例: -不是线程安全的(您必须注意比赛条件)。 -此外,由实例发出并连接到线程B中对象的插槽的信号不是直接的:通过复制所有方法参数并将所有内容放入要由线程B事件队列执行的事件中,插槽执行被推迟到稍后的时刻

鉴于此,您可以利用的解决方案如下

子类是QObject的子类

class SubClass : public QObject{
Q_OBJECT
[...]
}
线程A将运行以下方法来反序列化并用子类实例填充内存

void methodA(){  /this method is executed by thread A

 QThread* threadB; //a reference to the QThread related to thread B
 [...]
 MyQObject* instance = someFactoryMethod();

 //we push the ownership of instance from thrad A to thread B
 instance->moveToThread( threadB ); 

 //do something else

}
但是请注意,如果线程A需要对实例执行其他操作,那么这可能不够。特别是,线程A可能会触发MyQObject中定义的一些信号。这是不允许的,因为现在线程A不再是实例的所有者

在这种情况下,您需要推迟此类操作,并要求线程B执行该操作。这是通过使用QMetaObject::invokeLater方法实现的

InvokeLater允许您调用特定的插槽,要求线程B执行它

假设ClassInB是一个类,其实例在线程B中使用

class ClassInB : public QObject{
 Q_OBJECT

public:
    [...]
slots:
  void complexOperation(MyQObject* o){
    [...]
    emitSomeSignal();
  }
signals:

  void someSignal();
}
在将实例移动到线程B之后,我们需要对位于线程B中的ClassInB实例执行complexOperation(),该实例反过来也会发出一些信号()

为了能够使用MyQObject*作为调用器的参数,我们需要将其注册到元框架中。您需要:

  • 在定义MyQObject的.cpp中添加
    Q\u DECLARE\u元类型(MyQObject*)
  • 在使用该机制(例如,在main中)之前调用一次,
    qRegisterMetaType()

在创建它们的线程上,只需将它们移动到主线程即可<代码>自动*p=新的SomeQObject();p、 移动到线程(主线程)与反序列化的成本相比,创建QT对象的成本有多高?您能否反序列化为内存中的表示形式,然后在主线程中使用该表示形式来快速创建相应的QT对象?>>“在创建它们的线程上,只需将它们移动到主线程即可?”——我尝试了这一点,但应用程序仍然抱怨它的一些子线程仍然属于不同的线程(这里讨论的小部件是QGraphicscene)>>“与反序列化的成本相比,创建QT对象的成本有多高?能否将其反序列化为内存中的表示形式,然后在主线程中使用该表示形式快速创建适当的QT对象?”-----问题是序列化机制不知道它创建了什么类,但它需要立即创建它,以便能够初始化其成员。因此,这不是一个合理的解决方案。如果graphicsview在主线程中,那么在次线程中使用GraphicsCenter将不起作用,因为这些类不是线程afe,他们的互动将停止工作。
void methodA(){  //this method is executed by thread A
  QThread* threadB; //a reference to the QThread related to thread B
  ClassInB* instanceOnB;   //a reference to a ClassInB instance living in thread B
  [...]

   MyQObject* instance = someFactoryMethod();

   //we push the ownership of instance from thread A to thread B
   instance->moveToThread( threadB ); 

   //we ask thread B to perform some operation related to instance
   QMetaObject::invokeLater(instanceOnB, "complexOperation", Q_ARG(MyQObject*, instance) );

}