7

編集:

皆さんがコメントで教えてくれたことをやってみました... :

Citizen * c = new Citizen(this);

QThread thread;
c->moveToThread(&thread);

connect(&thread, SIGNAL(started()), c, SLOT(ProcessActions()));
thread.start();

これにより、さらに多くのエラーが発生します。

QThread: Destroyed while thread is still running
ASSERT failure in QThread::setTerminationEnabled(): "Current thread was not started with QThread.", file c:\ndk_buildrepos\qt-desktop\src\corelib\thread\qthread_win.cpp, line 542
Invalid parameter passed to C runtime function.
Invalid parameter passed to C runtime function.
QObject::killTimers: timers cannot be stopped from another thread

このエラーに問題があります... もう 2 日間この問題に悩まされており、解決策が見つかりません。

ヘッダ:

class Citizen : public QThread
{
Q_OBJECT    
    QNetworkAccessManager * manager;

private slots:
    void onReplyFinished(QNetworkReply* net_reply);

public:
    Citizen(QObject * parent);

    void run();
};

実装:

Citizen::Citizen(QObject * parent)
{
    manager = new QNetworkAccessManager;
    connect(_net_acc_mgr, SIGNAL(finished(QNetworkReply*)),
            this, SLOT(onReplyFinished(QNetworkReply*)));
}

void Citizen::onReplyFinished(QNetworkReply* net_reply)
{
    emit onFinished(net_reply);
}

void Citizen::run()
{
    manager->get(QNetworkRequest(QUrl("http://google.com"));

    QEventLoop eLoop;
    connect(manager, SIGNAL( finished( QNetworkReply * ) ), &eLoop, SLOT(quit()));
    eLoop.exec(QEventLoop::ExcludeUserInputEvents);

    qDebug() << "loaded google!";

    exec();
}

manager->get() が実行されると、次のエラーが発生します。

QObject: Cannot create children for a parent that is in a different thread.
(Parent is QNetworkAccessManager(0xc996cf8), parent's thread is QThread(0xaba48d8), current thread is Citizen(0xca7ae08)

eLoop.exec() が実行されると:

QObject::startTimer: timers cannot be started from another thread

私は次の方法でこのスレッドを開始します。

Citizen * c = new Citizen(this);
c->start();

なぜこれが起こるのですか?これを解決するには?

4

6 に答える 6

12
QObject: Cannot create children for a parent that is in a different thread.

これは、「元の」スレッドで呼び出されている Citizen のコンストラクターで QNetworkAccessmanager を作成しているためです。Citizen オブジェクトが新しいスレッドに移動されると、QNetworkAccessmanager のスレッド アフィニティは元のスレッドに設定されたままですが、実行呼び出しでは、新しいスレッドで QNetworkReply オブジェクト (およびおそらく他のオブジェクト) を作成しようとします。上記の警告が生成されます。

実行スロット (または Citizen オブジェクトが新しいスレッドに移動された後の任意の時点) でマネージャーを作成すると、それは発生しません。

ただし、まだいくつかの問題があります。たとえば、Citizen クラスは実際には QThread である必要はありません。それはそれを不必要に複雑にします。QObjectをサブクラス化するだけで十分です。通常のスロットを作成し、それを QThread::started() シグナルに接続するだけです。OrcunC が指摘したように、QThread インスタンスが適切にスコープされていることを確認する必要があります。

スレッド化の詳細: http://blog.qt.io/blog/2010/06/17/youre-doing-it-wrong/

例:

QThread *thread = new QThread;
thread->start();
Citizen *worker = new Citizen;
worker->moveToThread(thread);

//startWorking can be equivalent of the run function
//in your current implementation and this is where you should
//create the QNetworkAccessManager
QMetaObject::invokeMethod(worker,"startWorking");
于 2011-08-02T10:21:57.867 に答える
3

QThread: Destroyed while thread is still runningエラーが表示される理由に答えようとします。

こうすれば

void mtMethod () {

 Citizen * c = new Citizen(this);
 QThread thread;
 c->moveToThread(&thread);

 connect(&thread, SIGNAL(started()), c, SLOT(ProcessActions()));
 thread.start();
}

関数を終了すると、スレッド オブジェクトは破棄されますが、開始されたスレッドはまだ実行されています。Qt は、スレッドを停止するか、より大きなスコープでスレッド オブジェクトを作成する必要があることを警告しています。(つまり、クラスのメンバー関数にします)。このようなもの :

class myClass
{
virtual ~myClass ();
 QThread mythread;
};

myClass::~myClass
{
  mythread.stop ();
}

void myClass::mtMethod () {

     Citizen * c = new Citizen(this);
     c->moveToThread(&mythread);

     connect(&mythread, SIGNAL(started()), c, SLOT(ProcessActions()));
     mythread.start();
}
于 2011-08-02T06:14:13.893 に答える
1

最初のエラーに関連している可能性がありますが、startTimers エラーはわかりません。いずれにせよ、最初のエラーを修正できるはずです。私は Qt でこの問題に数回遭遇しましたが、初期化関数とクリーンアップ関数を作成することが、これを回避する「最良の」方法であることがわかりました。クラスのすべてのメンバーは、run が呼び出されるまで NULL に初期化されるポインターです。「最高」は引用符で囲まれていることに注意してください。異なる意見があるはずですが、私にとってはほとんどの状況で機能します。

ヘッダ

class Citizen : public QThread {
   Q_OBJECT

   QNetworkAccessManager * manager;

   private slots:
      void onReplyFinished(QNetworkReply* net_reply);
   public:
      Citizen(QObject * parent);
      void run();

   private:
      void initialize();
      void cleanUp();
 };

実装

Citizen::Citizen(QObject * parent) :
   manager(NULL) {
}

void Citizen::onReplyFinished(QNetworkReply* net_reply) {
   emit onFinished(net_reply);
}

void Citizen::run() {
   initialize();
   manager->get(QNetworkRequest(QUrl("http://google.com"));

   QEventLoop eLoop;
   connect(manager, SIGNAL( finished( QNetworkReply * ) ),
           &eLoop, SLOT(quit()));
   eLoop.exec(QEventLoop::ExcludeUserInputEvents);

   qDebug() << "loaded google!";
   exec();

   cleanUp();
}

void Citizen::initialize() {
   manager = new QNetworkAccessManager;
   connect(_net_acc_mgr, SIGNAL(finished(QNetworkReply*)),
           this, SLOT(onReplyFinished(QNetworkReply*)));
}

void Citizen::cleanUp() {
   delete manager;
   disconnect(_net_acc_mgr, SIGNAL(finished(QNetworkReply*)),
              this, SLOT(onReplyFinished(QNetworkReply*)));
}
于 2011-08-01T22:43:03.117 に答える
1

run が呼び出されるまで、新しいスレッドが存在するとは思わない。したがって、コンストラクターは run() とは別のスレッドです。manager オブジェクトの作成をコンストラクターから run() に移動するとどうなりますか? タイマーエラーではないにしても、最初のエラーは修正されると思います。

また、今でもあなたのようにスレッドを立てている人も多いと思いますが、こちらもチェックしてみてください

于 2011-08-01T16:02:43.913 に答える
1

スレッド アフィニティを考慮する必要があります。このエラー メッセージは嘘でも狂気でもありません。何が問題なのかを正確に伝えています。

于 2011-08-01T16:05:18.463 に答える
1

あなたの問題は、主に QThread をサブクラス化しようとしていることが原因です。ドキュメントでは推奨されていますが、QThread を使用する最良の方法ではありません。詳細とリンクについては、この質問と回答を参照してください。

于 2011-08-01T16:06:11.817 に答える