QBasicTimer :: stopを防ぐ方法:オブジェクトがスレッドレスになったときに警告に失敗しましたか?

6
Unslander Monica 2018-06-01 18:24.

QObjectsは、作業スレッドが前に終了すると、簡単にスレッドレスになる可能性があります。これが発生すると、タイマーがアクティブでなくなっても、QtはタイマーIDを解放しません。したがって、QBasicTimer::stop: Failed. Possibly trying to stop from a different thread警告が表示されます。これは主に表面的な結果をもたらしますが、タイマーIDのリークを示しているため、回避策があれば便利です。次の例で問題が発生します。

#include <QtCore>
int main(int argc, char *argv[]) {
   static_assert(QT_VERSION < QT_VERSION_CHECK(5,11,0), "");
   QCoreApplication app(argc, argv);
   QObject object;
   object.startTimer(1000);
   QThread workThread;
   workThread.start();
   object.moveToThread(&workThread);
   QTimer::singleShot(500, &QCoreApplication::quit);
   app.exec();
   workThread.quit();
   workThread.wait();
}

回避策でタイマーの割り当て方法を変更する必要がない場合、つまり、Qtがすでに実行している以上にタイマーを追跡する必要がない場合は便利です。

2 answers

3
Unslander Monica 2018-06-01 19:08.

簡単な解決策は、問題を防ぐことです。オブジェクトがスレッドレスになりそうな場合は、オブジェクトをスレッドハンドルの親スレッドに移動し、スレッド自体が破棄されようとしているときに、オブジェクトのタイマーを再確立して警告を防ぎます。

QObjectmoveToThread実装には2つの部分があります。

  1. QEvent::ThreadChangeからのオブジェクトに配信されますmoveToThreadQObject::eventこのイベントを使用して、オブジェクトでアクティブなタイマーをキャプチャして非アクティブ化します。これらのタイマーはリストにパッケージ化され、オブジェクトの内部_q_reactivateTimersメソッドに投稿されます。

  2. 宛先スレッドのイベントループは、メタコールをオブジェクトに配信します。 https://code.woboq.org/qt5/qtbase/src/corelib/kernel/qobject.cpp.html#_ZN14QObjectPrivate19_q_reregisterTimersEPv新しいスレッドで実行され、タイマーは新しいスレッドで再アクティブ化されます。次の場合に注意してくださいhttps://code.woboq.org/qt5/qtbase/src/corelib/kernel/qobject.cpp.html#_ZN14QObjectPrivate19_q_reregisterTimersEPv実行する機会がないため、タイマーリストが取り返しのつかないほどリークします

したがって、次のことを行う必要があります。

  1. オブジェクトがスレッドレスになりそうな瞬間をキャプチャし、それを別のスレッドに移動して、QMetaCallEventto_q_reactivateTimersが失われないようにします。

  2. 正しいスレッドでイベントを配信します。

など:

// https://github.com/KubaO/stackoverflown/tree/master/questions/qbasictimer-stop-fix-50636079
#include <QtCore>

class Thread final : public QThread {
   Q_OBJECT
   void run() override {
      connect(QAbstractEventDispatcher::instance(this),
              &QAbstractEventDispatcher::aboutToBlock,
              this, &Thread::aboutToBlock);
      QThread::run();
   }
   QAtomicInt inDestructor;
public:
   using QThread::QThread;
   /// Take an object and prevent timer resource leaks when the object is about
   /// to become threadless.
   void takeObject(QObject *obj) {
      // Work around to prevent
      // QBasicTimer::stop: Failed. Possibly trying to stop from a different thread
      static constexpr char kRegistered[] = "__ThreadRegistered";
      static constexpr char kMoved[] = "__Moved";
      if (!obj->property(kRegistered).isValid()) {
         QObject::connect(this, &Thread::finished, obj, [this, obj]{
            if (!inDestructor.load() || obj->thread() != this)
               return;
            // The object is about to become threadless
            Q_ASSERT(obj->thread() == QThread::currentThread());
            obj->setProperty(kMoved, true);
            obj->moveToThread(this->thread());
         }, Qt::DirectConnection);
         QObject::connect(this, &QObject::destroyed, obj, [obj]{
            if (!obj->thread()) {
               obj->moveToThread(QThread::currentThread());
               obj->setProperty(kRegistered, {});
            }
            else if (obj->thread() == QThread::currentThread() && obj->property(kMoved).isValid()) {
               obj->setProperty(kMoved, {});
               QCoreApplication::sendPostedEvents(obj, QEvent::MetaCall);
            }
            else if (obj->thread()->eventDispatcher())
               QTimer::singleShot(0, obj, [obj]{ obj->setProperty(kRegistered, {}); });
         }, Qt::DirectConnection);

         obj->setProperty(kRegistered, true);
      }
      obj->moveToThread(this);
   }
   ~Thread() override {
      inDestructor.store(1);
      requestInterruption();
      quit();
      wait();
   }
   Q_SIGNAL void aboutToBlock();
};

int main(int argc, char *argv[]) {
   static_assert(QT_VERSION < QT_VERSION_CHECK(5,11,0), "");
   QCoreApplication app(argc, argv);
   QObject object1, object2;
   object1.startTimer(10);
   object2.startTimer(200);
   Thread workThread1, workThread2;
   QTimer::singleShot(500, &QCoreApplication::quit);
   workThread1.start();
   workThread2.start();
   workThread1.takeObject(&object1);
   workThread2.takeObject(&object2);
   app.exec();
}
#include "main.moc"

このアプローチは、のすべての子を動的に追跡するように簡単に拡張できますobj。Qtは、そのような追跡を行うのに十分なイベントを提供します。

1
Mohammad Kanan 2018-06-01 19:06.

スレッド内から強制終了されるタイマーIDを保持します-by object

 int id = object.startTimer(1000);
 QThread workThread;
 workThread.start();
 object.moveToThread(&workThread);
 QTimer::singleShot(500, &QCoreApplication::quit);
 QObject::connect(&workThread, &QThread::finished, [&](){object.killTimer(id);});

...

Related questions

MORE COOL STUFF

ダイアナ妃は、8歳でウィリアム王子を寄宿学校に送るという決定に「涙を流した」

ダイアナ妃は、8歳でウィリアム王子を寄宿学校に送るという決定に「涙を流した」

ウィリアム王子が 8 歳のときに寄宿学校に通わせたことについて、ダイアナ妃がどのように感じたかを学びましょう。

シャキール・オニールは、レイカーズのスターが彼のチキン帝国を北テキサスに拡大するにつれて、ダラスの外に永住権を購入しました

シャキール・オニールは、レイカーズのスターが彼のチキン帝国を北テキサスに拡大するにつれて、ダラスの外に永住権を購入しました

Shaquille O'Neal は最近、Big Chicken レストラン帝国を拡大するため、ダラス郊外に住居を購入しました。

「90 日間の婚約者」: イヴが逮捕され、浮気スキャンダルの後、モハメドに対する家庭内暴力の容疑に直面している — 何が起こったのか?

「90 日間の婚約者」: イヴが逮捕され、浮気スキャンダルの後、モハメドに対する家庭内暴力の容疑に直面している — 何が起こったのか?

「90日の婚約者」シーズン9のスター、イヴ・アレラーノが逮捕され、モハメド・アブデルハメドへの暴行容疑で家庭内暴力の罪に問われている.

ナターシャ・リオンは、ピーウィー・ハーマンは「ビジネスで最高のGIFを送る」と言います

ナターシャ・リオンは、ピーウィー・ハーマンは「ビジネスで最高のGIFを送る」と言います

ナターシャ・リオンは、ピーウィー・ハーマン自身、ポール・ルーベンスと親密です。彼らの友情について彼女が言ったことを発見してください。

セントヘレナのジェイコブのはしごを登るのは、気弱な人向けではありません

セントヘレナのジェイコブのはしごを登るのは、気弱な人向けではありません

セント ヘレナ島のジェイコブズ ラダーは 699 段の真っ直ぐ上る階段で、頂上に到達すると証明書が発行されるほどの難易度です。

The Secrets of Airline Travel Quiz

The Secrets of Airline Travel Quiz

Air travel is far more than getting from point A to point B safely. How much do you know about the million little details that go into flying on airplanes?

Where in the World Are You? Take our GeoGuesser Quiz

Where in the World Are You? Take our GeoGuesser Quiz

The world is a huge place, yet some GeoGuessr players know locations in mere seconds. Are you one of GeoGuessr's gifted elite? Take our quiz to find out!

バイオニック読書はあなたをより速く読むことができますか?

バイオニック読書はあなたをより速く読むことができますか?

BionicReadingアプリの人気が爆発的に高まっています。しかし、それは本当にあなたを速読術にすることができますか?

ハードコアシェフのゴードンラムゼイが最もハードコアなフェラーリをドライブ

ハードコアシェフのゴードンラムゼイが最もハードコアなフェラーリをドライブ

有名シェフのゴードン・ラムゼイの味わいと爆発的なとんでもない悪意に相当する車を考えざるを得なかったとしたら、ラムゼイ自身が所有している新しいフェラーリF12tdfを思い浮かべるでしょう。ちょっとそれを見てください、彼は実際にこのビデオでちょっといいです!彼は通りの農民と一緒に写真を撮るのをやめ、写真を撮るために若者を車の中に座らせさえしているようです。

私たちの最初の宇宙農場にはジャガイモよりもはるかに良い選択肢があります

私たちの最初の宇宙農場にはジャガイモよりもはるかに良い選択肢があります

火星人は、宇宙のジャガイモ栽培を、かなり美味しくも簡単でもないにしても、確かにもっともらしいものにしました。しかし、私たちが本当に宇宙に住むつもりなら、ジャガイモは絶対に私たちの最初の農業の選択であるべきではありません。

ランドローバーは新しいボディスタイルで10倍以上のディフェンダーを売りたい

ランドローバーは新しいボディスタイルで10倍以上のディフェンダーを売りたい

ランドローバーのデザインチーフであるジェリーマガバーンは、次のランドローバーディフェンダーが私たちが見たレゴのようなコンセプトに「似ていない」ことを確認しましたが、彼は次回はもっと売りたいと言っています。はるかに。

アダムサンドラーは、Netflixが彼の人種差別的な映画について非常に冷静だったと言います

アダムサンドラーは、Netflixが彼の人種差別的な映画について非常に冷静だったと言います

アダムサンドラーのNetflix限定映画、リディキュラスシックスは、平均的なアダムサンドラー映画よりも見栄えが悪いです。マグニフィセントセブンのパロディーであるこの映画は、ネイティブアメリカンと彼の5人の異母兄弟が、誘拐された父親を救おうとしているところを追っています。

ケイト・ミドルトンとウィリアム王子は、彼らが子供たちと行っているスパイをテーマにした活動を共有しています

ケイト・ミドルトンとウィリアム王子は、彼らが子供たちと行っているスパイをテーマにした活動を共有しています

ケイト・ミドルトンとウィリアム王子は、子供向けのパズルの本の序文を書き、ジョージ王子、シャーロット王女、ルイ王子と一緒にテキストを読むと述べた.

事故で押しつぶされたスイカは、動物を喜ばせ水分補給するために野生生物保護団体に寄付されました

事故で押しつぶされたスイカは、動物を喜ばせ水分補給するために野生生物保護団体に寄付されました

Yak's Produce は、数十個のつぶれたメロンを野生動物のリハビリ専門家であるレスリー グリーンと彼女のルイジアナ州の救助施設で暮らす 42 匹の動物に寄付しました。

デミ・ロヴァートは、新しいミュージシャンのボーイフレンドと「幸せで健康的な関係」にあります: ソース

デミ・ロヴァートは、新しいミュージシャンのボーイフレンドと「幸せで健康的な関係」にあります: ソース

8 枚目のスタジオ アルバムのリリースに向けて準備を進めているデミ ロヴァートは、「スーパー グレート ガイ」と付き合っている、と情報筋は PEOPLE に確認しています。

Plathville の Kim と Olivia Plath が数年ぶりに言葉を交わすことへようこそ

Plathville の Kim と Olivia Plath が数年ぶりに言葉を交わすことへようこそ

イーサン プラスの誕生日のお祝いは、TLC のウェルカム トゥ プラスビルのシーズン 4 のフィナーレで、戦争中の母親のキム プラスと妻のオリビア プラスを結びつけました。

水門の修理

水門の修理

天王星と海王星の間の領域に向かって宇宙を 3/4 g の低温で航行しながら、私たちは数週間燃え続けていました。Dawson Trawler の科学者が Yggdrasil ポータルと呼んだもの。

美しいもの

美しいもの

女性として、私は通常、関係を築くことをためらっています。私はいつも彼らに負けないように苦労しました。私は誰かと共有したいという衝動と戦わなければなりません。

逃走中の女性からの発信

最も家が必要なときに家のように感じる場所はありません。

逃走中の女性からの発信

私は誰よりも移動しました。父が住んでいた土地には、父が 1 歳馬を折るミニチュアの競馬場がありました。

死にゆく男から学んだ最大の人生の教訓

彼は、私たちが持っているのはこの現在の瞬間だけであることを知るのが遅すぎました。

死にゆく男から学んだ最大の人生の教訓

ブラッドは、カーキ色のショート パンツとポロ シャツを着たまま、白いゴルフ グローブを両手で高く引っ張ったまま、ベッドルームに入ってきました。彼は満面の笑みを浮かべながら、「今年は私の人生で最高の年だったと思います!」と言いました。通常は保守的な消費者である私たちは、通常とは異なることをしました。

Language