Qt4のスレッドではまったこと(備忘録)

Qt4を利用したアプリケーション開発をしていてドはまりしてしまったので忘れないうちにメモ。

Qt(最新リリースはQt4.3)は多機能なツールキットです。クロスプラットフォームに対応したGUI開発はもちろん、ネットワークやXMLなどを扱うためのプリミティブなライブラリが一通りそろっています。GUIに限らずすべてがクロスプラットフォームですから、同一コードベースでWindowsにもLinuxにもMacにも対応できます。

対応言語はC++ですが、Java向けのものも提供されています。Javaならともかく、C++の場合はメモリ管理がちょっといやなところですが、Qt内部のものに関してはある程度Qtのライブラリが管理してくれるようです。

それからQtでのプログラミングにおける特徴は、Qtのオブジェクト(QObject)のサブクラスたちはシグナルとスロットというものを持っていて、誰かのシグナルをほかの誰かのスロットに接続していくことによってイベントドリブンなコードになることです。

AS3とかでイベントに絡むコードを書くと

this.addEventListener(MouseEvent.DOUBLE_CLICK, this.mouseDCHandler);

こんな感じ(イメージなので不正確)になると思いますが、これをQt風(あくまでイメージ)として書くとこんな感じになります。

connect(this, SIGNAL(doubleClicked()), this, SLOT(DCHandler()));

まあそんなに違いはないですね。あとASでこういうことができるかどうかはわからないのですが、Qtの場合シグナルを別のシグナルに直接接続することができます。

connect(this, SIGNAL(doubleClicked()), this, SIGNAL(clicked()));

つまり、何かのイベントをトリガにした別のイベントの発行をハンドラなしで実現できるわけです。(シグナルのシグネチャによって制限はありますが。)

発信されるシグナルはその場で即座に処理させることも、キューイングさせて、スレッドのイベントループで処理させることも可能です。このあたりはマルチスレッドなプログラムを書くときなどに絡んできます。

シグナルの機構自体は下のレイヤであるイベント処理によって実装されているようなので、シグナルを利用する場合はもちろん中でイベントループがまわっていないといけません。シグナルはconnect();が呼ばれたスレッドのイベントループで処理されるようなので、マルチスレッドなコードを書くときは少し注意が必要です。

Qtの場合QThreadというクラスのサブクラスを作ることでスレッドを作ります。JavaみたいにRunnableインタフェースの実装とかはないようです。そして、お察しのようにrun()のオーバーロードで処理を記述するのですが、一通りの処理が終わったあとにはexec();を呼び出してイベントループを回すようにしないといけません。

void MyThread::run(){
// 処理あれこれ
exec();
}

上でも書きましたが、シグナル、イベントはスレッドのイベントループで処理されるので、スレッドが終わってしまうと途中でconnect();したシグナルたちは行き場がなくなってしまい、結果として期待した動きをしてくれなくなります。APIリファレンスにはちゃんとexec();しているコードがあるのにそれに気づかないで僕は半日ほど消えました。

それからconnect();の呼び出しに渡されるSIGNAL()やSLOT()の中身はコンパイル時にチェックされず、実行時になってそんなシグナルねーよ、とか言われるのでこっちも注意です。

上記2つ、どっちもちゃんとドキュメントとか読んでおけば大丈夫なのですが、自戒のためにもこうやって書き残しておきます。

Qt4のスレッドではまったこと(備忘録)” への1件のフィードバック

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください