2

オブジェクト インスタンスを、オブジェクトに対して SLOT メソッドを実行する不透明なモジュール (コールバック) に渡しています。呼び出しモジュールは別のスレッドにあります。メインスレッドでメソッドを実行する必要があります。シグナルとスロットでこれを行うことができると思っていましたが、シグナルされたメソッドはまだ呼び出し元のスレッドで実行されています。moveToThread() を使用してオブジェクトを呼び出し元のスレッドに移動する必要はないと思います-アプリケーションのメインスレッドにシグナルを送信するメカニズムはありませんか?

MyClass::MyClass(...)
{
   OtherClass::getInstance()->setCallback(this);
   connect(this, SIGNAL(mySignalToMainThread()), this, SLOT(doThisOnMainThread()));
}

// Public slot, called by OtherClass on its own thread.
void MyClass::someCallback() 
{
   emit mySignalToMainThread();
}

void MyClass::doThisOnMainThread()
{
   // AHHH! I am still on callers thread.
}
4

2 に答える 2

1

最初は、MyClass が存在するスレッド コンテキスト以外のスレッド コンテキストからのシグナルの発行が問題になる可能性があると考えました。ただし、Qt スレッドのドキュメントには次のように記載されています

...シグナル発行はスレッドセーフであるため、QThread::run() 実装からシグナルを安全に発行できます。

それはその考えをほとんど打ち砕きます。そして、ドキュメントに次のように記載されてQt::AutoConnectionいる を使用しています。

シグナルが受信オブジェクトとは異なるスレッドから送信された場合、シグナルはキューに入れられ、Qt::QueuedConnection として動作します。それ以外の場合、スロットは直接呼び出され、Qt::DirectConnection として動作します。接続のタイプは、信号が発信されたときに決定されます。

特に重要な最後のビット。このコードを書くとしたら:

void MyClass::someCallback() 
{
   Q_ASSERT(QThread::currentThread() != this->thread());
   emit mySignalToMainThread();
}

void MyClass::doThisOnMainThread()
{
   Q_ASSERT(QThread::currentThread() == this->thread());
}

アサートの失敗はないと思いますが、失敗することをお勧めします。Qtのドキュメントが間違っているか、この問題にはあなたが言及した以上のものがあると結論付けなければなりません。

于 2012-09-26T18:56:29.913 に答える
0

それは私のために働いています。あなたの実装を私が以下に持っているものと比較して、どこが違うのか見てみてください。欠落している詳細を推測して、できる限り厳密にあなたの慣習に従おうとしました:

my_class.h

class MyClass : public QObject {
  Q_OBJECT

public:
  explicit MyClass(QObject *parent = 0);

signals:
  void mySignalToMainThread();

public slots:
  void someCallback();
  void doThisOnMainThread();
};

my_class.cpp

MyClass::MyClass(QObject *parent) :
  QObject(parent) {
  std::cout << Q_FUNC_INFO <<  QThread::currentThreadId() << std::endl;
  OtherClass::getInstance().setCallback(this);
  connect(this, SIGNAL(mySignalToMainThread()), SLOT(doThisOnMainThread()));
}

void MyClass::someCallback() {
  std::cout << Q_FUNC_INFO <<  QThread::currentThreadId() << std::endl;
  emit mySignalToMainThread();
}

void MyClass::doThisOnMainThread() {
  std::cout << Q_FUNC_INFO <<  QThread::currentThreadId() << std::endl;
}

other_class.h

class OtherClass : public QObject {
  Q_OBJECT

public:
  static OtherClass& getInstance();
  void setCallback(MyClass *cb);

public slots:
  void doCallback();

private:
  explicit OtherClass(QObject *parent = 0);

  MyClass *cb_;
};

other_class.cpp

OtherClass::OtherClass(QObject *parent) : QObject(parent) {
  std::cout << Q_FUNC_INFO <<  QThread::currentThreadId() << std::endl;
}

OtherClass& OtherClass::getInstance() {
  std::cout << Q_FUNC_INFO <<  QThread::currentThreadId() << std::endl;
  static OtherClass singleton;
  return singleton;
}

void OtherClass::doCallback() {
  std::cout << Q_FUNC_INFO <<  QThread::currentThreadId() << std::endl;
  cb_->someCallback();
}

void OtherClass::setCallback(MyClass *cb) {
  std::cout << Q_FUNC_INFO <<  QThread::currentThreadId() << std::endl;
  cb_ = cb;
}

main.cpp

int main (int argc, char **argv) {
  QApplication app(argc, argv);

  MyClass c;

  QThread other;
  OtherClass::getInstance().moveToThread(&other);
  other.connect(&other, SIGNAL(started()),
                &OtherClass::getInstance(), SLOT(doCallback()));
  other.start();

  QMainWindow w;
  w.show();

  return app.exec();
}

出力例:

__thiscall MyClass::MyClass(class QObject *)00001108
class OtherClass &__cdecl OtherClass::getInstance(void)00001108
__thiscall OtherClass::OtherClass(class QObject *)00001108
void __thiscall OtherClass::setCallback(class MyClass *)00001108
class OtherClass &__cdecl OtherClass::getInstance(void)00001108
class OtherClass &__cdecl OtherClass::getInstance(void)00001108
void __thiscall OtherClass::doCallback(void)000015AC
void __thiscall MyClass::someCallback(void)000015AC
void __thiscall MyClass::doThisOnMainThread(void)00001108
于 2012-09-26T20:06:39.223 に答える