web-dev-qa-db-ja.com

QThreadとstd :: thread

「pthreadvsstd :: thread」と「QThreadvspthread」で異なるトピックを見ましたが、「std :: threadvsQThread」では見ませんでした。

3Dプリンターを駆動するソフトウェアをプログラムする必要があり、スレッドを使用する必要があります。安全性を常にチェックするスレッド、印刷プロセスを実行するスレッド、各ハードウェアコンポーネント(移動、ジェットなど)を個別に駆動するスレッドなどがあります。このプログラムはC++ 11を搭載したWindows用に開発されています。/Qt。

最初はQThreadを使いたかったのですが、たとえば、AnthonyWilliamsの「C++ Concurrency in Action」を読んでいる間、QThreadではstd :: threadほど多くのことを実行できないようです 、QThreadでは不可能と思われるstd::thread t1(&Class::function, this, ...);のようなことを行うことで、std :: threadに別のスレッドから関数を実行するように依頼できることがわかりました。

私が最も望んでいるメカニズムは、関数を現在のスレッドで実行するか、別のスレッドで実行するかを示す方法です。

どちらを選択しますか、またその理由は何ですか?

11
ElevenJune

QThreadは単なるスレッドではなく、スレッドマネージャーでもあります。スレッドでQtを再生したい場合は、QThreadが最適です。 Qtは、最新のプログラミングのほとんどと同様に、イベント駆動型です。これは、「スレッドに関数を実行させる」よりも少し複雑で柔軟性があります。

Qtでは、通常、QThreadと一緒にワーカーを作成し、ワーカーをそのスレッドに移動します。その後、そのワーカーオブジェクトに対してイベントシステムによって呼び出されるすべての関数が、ワーカーオブジェクトがアフィニティを持つスレッドで実行されます。に。

したがって、機能をさまざまなワーカーオブジェクト(たとえば、SafetyCheckerPrinterServoDriverJetDriverなど)にカプセル化して、それぞれのインスタンスを作成し、移動することができます。それを専用のスレッドに接続すると、設定が完了します。きめ細かいイベントを使用する代わりに「ブロック」する関数を呼び出したり、アトミックまたはミューテックスを使用してスレッド間同期を実行したりすることもできます。メイン/ GUIスレッドをブロックしない限り、これに問題はありません。

キュー接続が含まれるマルチスレッドシナリオでは、直接接続や仮想ディスパッチよりもわずかに遅いため、プリンタコードイベント駆動型を実行することはおそらく望ましくありません。マルチスレッドをきめ細かくしすぎると、実際にパフォーマンスが大幅に低下する可能性があります。

そうは言っても、Qtの非GUIのものを使用することには独自のメリットがあり、よりクリーンで柔軟なデザインをはるかに簡単にすることができます。また、適切に実装すれば、マルチスレッドのメリットを享受できます。イベント駆動型アプローチを使用して全体を管理することもできます。これは、はるかに低レベルの構成であるstd::threadのみを使用するよりもはるかに簡単です。イベント駆動型アプローチを使用して、設計のセットアップ、構成、監視、および管理を行うことができます。重要な部分は、補助スレッドのブロック機能で実行して、可能な限り低い同期オーバーヘッドできめ細かい制御を実現できます。

明確にするために、他の2つの回答はすでに行っており、コメントで述べたように、非同期タスクは実際には制御アプリケーションを対象としていないため、回答は非同期タスクの実行に焦点を当てていません。これらは、メインスレッドをブロックしたいよりも時間がかかる小さなタスクの実行に適しています。推奨されるガイドラインとして、25ミリ秒以上かかるものはすべて非同期で実行することをお勧めします。一方、印刷は数分または数時間かかる場合があり、制御機能を並行して同期を使用して継続的に実行することを意味します。非同期タスクでは、制御アプリケーションのパフォーマンス、遅延、および順序が保証されません。

14
dtech

_std::thread_とQThreadの主な問題は、缶に書かれていることを実行することです。つまり、1つのスレッドを作成し、おそらく1つのことだけを実行するスレッドを作成します。 _std::thread_を使用して関数を「同時に」実行することは非常に無駄です。スレッドは高価なリソースであるため、関数を実行するためだけに作成するのは通常やり過ぎです。

std::thread t1(&Class::function, this, ...)は素晴らしく見えますが、通常は時期尚早の悲観論であり、「同時に物事を行う」ための普遍的な方法としてそれを示唆することは私見では間違っています。あなたはそれよりもうまくやることができます。

  1. ワーカースレッドで関数/ファンクター/メソッドを同時に実行する場合は、_QtConcurrent::run_または_std::async_を使用します。

    _QtConcurrent::run_はデフォルトでデフォルトのスレッドプールを使用しますが、QThreadPoolの独自のインスタンスを渡すこともできます。典型的なケースは、CPUバウンドタスクにデフォルトのスレッドプールを使用することです。計算、画像変換、レンダリングなど、専用のより大きなI/Oスレッドプールを使用して、使用を余儀なくされているAPIの制限のためにブロックしている操作を実行します(たとえば、多くのデータベースライブラリはブロックAPIのみを提供します。デザインは根本的に壊れています)。例:

    _// interface
    QThreadPool * ioPool();
    
    // implementation
    Q_GLOBAL_STATIC(QThreadPool, ioPool_impl);
    QThreadPool * ioPool() { return ioPool_impl; }
    _
  2. QObjectを別のスレッドに存在させたい場合(おそらく他のオブジェクトと共存させたい場合)、QThreadを使用してから、moveToThreadを使用してオブジェクトをそのスレッドに移動します。

    ワーカースレッドからシグナルを発行してスレッドセーフにデータをメインスレッドに渡すのはイディオムです。例えば。レスポンシブGUIが必要で、ワーカースレッドのディスクから画像をロードしたいとします。

    _class MyWidget : public QWidget {
      QLabel m_label;
      ...
      Q_SIGNAL void setImage(const QImage &);
     public:
      MyWidget() {
       ...
       connect(MyWidget, &MyWidget::setImage, this, [this](const QImage & image){
        m_label.setPixmap(QPixmap::fromImage(image));
       });
       QtConcurrent::run(ioPool(), [this]{ setImage({"/path/to/image.png"});  });
      }
    };
    _
7
Kuba Ober

スレッドをQtシステムに統合したい場合(信号を送信したり、特定のスロットに接続したりする必要があるなど)、QThreadは便利です。

QThreadのレイアウトはまだ作成されているので、「古い」c ++で動作します。スレッドで実行するためだけに、クラスとこのすべてのオーバーヘッド(コードと入力に関する)を作成する必要があります。

単にスレッドを開始したいだけなら、c ++ 11 std::threadは、記述しなければならない冗長性/コードが少なくなります。ラムダまたは関数ポインターを使用するだけで、必要な数の引数を指定できます。したがって、単純なスレッド化の場合は、QThreadsよりもc ++ 11スレッドをお勧めします。

もちろん、どちらを好むかは意見の問題です。


Qtにはいくつかの異なる高レベルのスレッドオブジェクトがありますが、C++にはありません。基本的なスレッドの代わりにそれらのいくつかが必要な場合、または基本的なスレッドはまったく必要ないが、それらの方が適している場合は、これらを調べることをお勧めします。

QThreadPoolのように、または単に QTimer のように、物事を待つ必要がある場合。 Here は、Qtのベアスレッドの代替案に関するいくつかの記事です。

QConcurrentは、たとえばc ++ 11 futureasyncにも近く、実行可能なオプションのスレッドプールもあります。

6
Hayt