C++ 将对象移动到其他线程
我的应用程序使用自定义序列化机制 阶段1)该机制在单独的线程上加载数据集群,并在其中创建所有适当的对象,依此类推 阶段2)一旦它们全部反序列化,它将它们交给主应用程序线程,并在那里完成序列化,例如设置对象之间的连接等 这个机制是对我的框架的一个新的补充——在此之前,我正在反序列化主线程上的所有内容 我遇到的问题是,在反序列化过程中创建的一些对象是Qt对象(基本上是一堆小部件)。 它们都记录创建它们的线程的ID。当“第二阶段”到来时,这些对象开始抱怨它们都不属于这个线程,因此无法发送信号等等 所以我在QObject上找到了一个名为“moveToThread”的方法。不过,这个小错误不是很有用,因为它执行检查并防止将对象从不同的线程移动到当前线程(为什么要破坏约束,我不知道) 有人知道我该怎么做吗?我可以保证这些对象只能在一个单独的线程上创建,从那时起,它们都将在主线程上运行 谢谢,C++ 将对象移动到其他线程,c++,multithreading,qt,C++,Multithreading,Qt,我的应用程序使用自定义序列化机制 阶段1)该机制在单独的线程上加载数据集群,并在其中创建所有适当的对象,依此类推 阶段2)一旦它们全部反序列化,它将它们交给主应用程序线程,并在那里完成序列化,例如设置对象之间的连接等 这个机制是对我的框架的一个新的补充——在此之前,我正在反序列化主线程上的所有内容 我遇到的问题是,在反序列化过程中创建的一些对象是Qt对象(基本上是一堆小部件)。 它们都记录创建它们的线程的ID。当“第二阶段”到来时,这些对象开始抱怨它们都不属于这个线程,因此无法发送信号等等 所以
涉及多线程时,必须小心处理QoObject的PAKSA实例或QoObject子类的任何实例。 请参阅,以获取对该主题的介绍 假设应用程序包含两个线程A和B。 假设线程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()代码>
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) );
}