マルチスレッドQtアプリケーション(1)
能書き
マルチスレッドをQtで再現する方法はいくつかあるが、
その中で、QThreadの継承を利用するものを紹介する。
コード:特にシンプルな例
まずはシンプルな例として、次のコードを書いてみた。
ヒープ領域を解放していなかったり、プログラムの終了条件がなかったり、
いろいろといい加減だが許してもらおう。
Q_DECL_OVERRIDEは、C++11以降ではoverrideに置換される。
このキーワードはもし無くてもエラーは生じない。
しかし、明記することで予期せぬ人的バグを回避できる。
QThreadのインスタンスをstart()すると、run()が内部的に呼び出される。
実行結果は次のとおりである。
Sub: SubThread(0x1881fe17100)
実行結果は毎回異なるが、マルチスレッドが達成されていることは確認できる。
しかし、この方法には思わぬ落とし穴がある。
コード:うまくいかない例
直前の例に、一部を追加しただけのものだ。
マルチスレッドに親しんだ人から見れば、奇ッ怪なコードに見えることだろう。
しかし、直感的には実現できそうに写る。
コンストラクタ、メンバ関数、スロットとその呼び出しを追加した。
実行結果は、次のとおりである。
Constructor: QThread(0x1b755747c70)
Func: QThread(0x1b755747c70)
Sub: SubThread(0x1b755749ad0)
Slot: QThread(0x1b755747c70)
この実行結果の意味がわかるだろうか?
五つの出力のうち、下四つはSubThreadのメンバ関数によるものである。
しかし、スレッドのIDを見てみると、『Sub』以外はすべて同一である。
内的に呼び出される『run』関数以外、マルチスレッドの恩恵を受けられない。
原因と解決策
『原因』などと書いたが、これはQtの仕様通りの動作である。
『うまくいかない例』のようなインターフェースのまま、どう設計すればよいか?
継承ではなく、委譲を用いることでその要求を達成できる。
留意点
異なるスレッド間の関数呼び出しは本当は危険らしい。
面倒でもシグナル/スロットを用いると安全に実装できる。