3

私のアプリケーションは、カスタムのシリアル化メカニズムを使用しています。

フェーズ 1 ) メカニズムはデータのクラスターを別のスレッドにロードし、そこにすべての適切なオブジェクトを作成します。

フェーズ 2 ) それらがすべて完全に逆シリアル化されると、メイン アプリケーション スレッドに引き渡され、オブジェクト間の接続を設定するなどして、そこでシリアル化を終了します。

このメカニズムは、私のフレームワークに新たに追加されたものです。それ以前は、メイン スレッドですべてをデシリアライズしていました。

私が抱えている問題は、逆シリアル化中に作成されるオブジェクトの一部が Qt オブジェクト (基本的にはウィジェットの束) であることです。それらはすべて、作成されたスレッドの ID を記録します。そして、「フェーズ 2」の時が来ると、これらのオブジェクトは、すべてこのスレッドに属していないため、シグナルを送信できないなどと不平を言い始めます。

そこで、「moveToThread」と呼ばれる QObject のメソッドを見つけました。ただし、チェックを実行し、オブジェクトを別のスレッドから現在のスレッドに移動するのを防ぐため、小さなバガーはあまり役に立ちません (なぜ制約をスカウトするのか、私には手がかりがありません)。

どうすればこれを実行できるか考えている人はいますか?オブジェクトは別のスレッドでのみ作成され、その時点から、それらはすべてメイン スレッド上で生きて動作することを保証できます。

ありがとう、パクサス

4

1 に答える 1

4

QObject のインスタンス、または QObjects のサブクラスのインスタンスは、マルチスレッドに関しては注意して処理する必要があります。トピックの紹介については、このページをご覧ください。

アプリケーションが 2 つのスレッドABで構成されているとします。スレッド Aがオブジェクト QObjectインスタンスを作成するとします。

インスタンスはスレッド A に存在すると言われています。これは、次のことを意味します: - スレッド A に存在する他のすべてのオブジェクトに対してシグナルを直接送受信できます。 - スレッド A から myInstance のメソッドに対して行われるすべての呼び出しは、スレッドセーフです。

一方、他のスレッド Bからのインスタンスへのアクセス: - スレッドセーフではありません (競合状態に注意する必要があります)。- さらに、インスタンスによって発行され、スレッド B のオブジェクトのスロットに接続されたシグナルは直接的ではありません。スロットの実行は、すべてのメソッド パラメータをコピーし、スレッド B のイベント キューによって実行されるイベントにすべてを配置することによって、後の瞬間に延期されます。

これを考えると、悪用できる解決策は次のとおりです。

SubClass は QObject のサブクラスです。

class SubClass : public QObject{
Q_OBJECT
[...]
}

スレッド A は、次のメソッドを実行して、デシリアライズし、メモリに SubClass インスタンスを設定します。

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 がinstanceで他の操作を実行する必要がある場合、これでは不十分な場合があることに注意してください。特に、スレッド 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()を実行する必要があります。これにより、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 フレームワークに登録する必要があります。次のことを行う必要があります。

  • Q_DECLARE_METATYPE(MyQObject*)MyQObject を定義する .cppを追加します
  • メカニズムを使用する前に(たとえば、メインで)一度呼び出します。qRegisterMetaType<MyQObject*>();
于 2013-07-11T15:18:34.233 に答える