マルチスレッドQtアプリケーション(2)
能書き
前回の記事の続きとして見てもよいだろうし、そうでなくてもよいだろう。
マルチスレッドをQtで再現する方法はいくつかあるが、
その中で、QThreadにタスクを委譲するものを紹介する。
簡単な例
まず、特に簡単なコードを示す。
異なるスレッド間で直接関数を呼び出すことは危険だが、ここでは無視する。
その他もいろいろいい加減なコードであるが、許してもらいたい。
実行結果は次のとおり。
Main: QThread(0x24230a65230)
Func: QThread(0x24230a68820)
Func: QThread(0x24230a68820)
マルチスレッドが実現されていることがわかる。
必要な手順
委譲を用いてマルチスレッドを実現するために必要な手順は以下のとおり。
- 別スレッドで実行したい処理を担うクラスを、QObjectを継承して作る。
- そのインスタンス(subObject)をヒープ領域に生成する。
SubObject *subObject = new SubObject(); - QThreadのインスタンス(subThread)をヒープ領域に生成する。
QThread *subThread = new QThread(); - subObjectの所有権をsubThreadに移す。
subObject->moveToThread( subThread ); - subThreadの処理を開始する。
subThread->start();
上記の処理は、source.cppの17-19行目に実装されている。
4番目の手順、5番目の手順を抜かしても、ビルドエラーは生じない。
予期通りの動作をしないときは、このようなミスをしている恐れがある。
異なるスレッド間で直接関数を呼び出してはいけない理由
例えば、先のコードを一部改造して、次のようなコードを書いたとする。
subThreadのstart()をコメントアウトし、シグナル/スロットを追加している。
実行結果は次のとおりである。
Main: QThread(0x1b9868d5300)
Func: QThread(0x1b9868d89b0)
emit complete
Func: QThread(0x1b9868d89b0)
emit complete
結果を見てわかるように、スロットが呼び出されていない!
これはなぜか。
実はスロットは、シグナルが発呼された直後に呼び出されるのではない。
スロットが所属するスレッドのキューに組み込まれるだけだ。
スレッドが開始されなければ、もちろんキューは処理されない。
それために、先の実行結果が出たのである。
直接関数を呼び出してしまっては、スレッドが開始していようがいまいが、
関係なしに即時実行してしまうこととなる。