将对象移至其他线程

moving an object to a different thread

本文关键字:其他 线程 对象      更新时间:2023-10-16

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

阶段1 )机制将数据簇加载在单独的线程上,在那里创建所有适当的对象,等等。

阶段2 )一旦它们全部被完全挑选,它将它们交给主应用程序线程,并通过例如在对象之间设置连接等来完成序列化。

。 。

这种机制是我框架的新补充 - 在此之前,我在主线程上都可以阐明所有内容。

我遇到的问题是,在deserializatiuon期间创建的某些对象是QT对象(基本上是一堆窗口小部件)。他们都记录了创建的线程的ID。当"第二阶段"的时间到来时,这些对象开始补充它们都不属于此线程,因此无法发送信号等。

因此,我在qobject上找到了一种方法,称为" movetothread"。但是,Little Bugger并不是很有帮助,因为它执行了检查并防止将对象从其他线程移动到当前线程(为什么要限制,我没有线索)。

有人知道我该怎么做?我可以保证这些对象只能在单独的线程上创建,从那时起,它们都将在主线程上生活和操作。

谢谢paksas

qObject的实例,或者在多线程中必须谨慎处理qobjects的任何实例。查看此页面以介绍该主题。

假设您的应用程序由两个线程 A B 组成。假设线程a 创建对象qobject 实例

实例 活作于线程a 。这意味着: - 它可以直接将信号发送给居住在线程A中的所有其他对象。 - 从线程A进行对Myinstance方法的所有调用均为线程安全

另一方面: - 不是线程安全的(您必须照顾种族条件)。 - 此外,由实例发出并连接到线程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需要在实例上执行其他操作,这可能是不够的。特别是可能会触发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的实例上执行 complectoperation(),这又会发出someSignal()。

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) );
}

要能够将myqobject*用作 InvokElater 的参数,我们需要将其注册到Meta框架中。您需要:

  • 在.cpp中添加 Q_DECLARE_METATYPE(MyQObject*)定义myqobject
  • 在使用该机制之前一次致电(例如在主机中),qRegisterMetaType<MyQObject*>();

只需用 QTimer::singleShot(int msec, const QObject *receiver, PointerToMemberFunction method)替换函数调用即可在另一个线程中运行一个插槽,因为根据文档,它从目标线程执行插槽。

这样,您就不需要以任何方式打扰更改代码,或者想知道当前对象是否在同一线程中,等等。