QObject のインスタンス、または QObjects のサブクラスのインスタンスは、マルチスレッドに関しては注意して処理する必要があります。トピックの紹介については、このページをご覧ください。
アプリケーションが 2 つのスレッドAとBで構成されているとします。スレッド 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*>();