yendo weblog


Gtk2-Perl でのバックグラウンド動作

Gtk2-Perl で Twitter クライアント Twitim を作った折りのメモ。 アプリ動作時にウェブにアクセスすると、その間 GUI が固まってしまう。 これを回避するにはウェブへのアクセスをバッググラウンドで行なう必要がある。 ちなみに、ちょっと哀しいけど結論だけなら 最後の「もっと簡単な方法」だけ読めば十分みたい。

分岐 fork

バックグラウンド動作のための分岐には、 スレッドやフォークがある。このような目的で スレッドを簡単に使うには POE があるようだがちょっとおおげさすぎる。 スレッドは UNIX 環境以外でも使えるのだろうが面倒だし、 Gtk2-Perl の FAQ でもお勧めしないとある。 なお、ruby なら間違いなくスレッドなのだろう。 Gtk2-Perl のアプリではバックグラウンド動作の例があまり 見つからなかったが、gnview はスレッドを使っている。

今回は AnyEvent を使っていることもあり、なるべく単純にと伝統的なフォークを使う。 AnyEvent は Gtk のイベントとなら協調して動作するが、 スレッドとか POE とかとはどうなのか不安だったこともある。 ただフォークでも注意が必要。 子プロセスの終了には use POSIX; の上、POSIX::_exit(1) する必要あり。 そうしないと X のエラーが起こる。 FAQ に情報 あり。 またその返り値は必ず指定する。 指定しないと X のエラーが起こる。はまった。返り値はまぁ 1 でしょう。

通信 pipe

子プロセスから親プロセスに、通信結果を渡すプロセス間通信だと、 パイプや共有メモリが一般的。 変数で渡すなら共有メモリもいいが、基本スカラー変数しか渡せない。 (共有メモリについてもサンプルがある。 IPC-ShareLite は簡単。)

今回はパイプを使う。 サンプル あり。pipe() をつかって、親と子を繋ぐ pipe ハンドラを指定する。 use IO::Handle; の上バッファに貯めないよう autoflush させた方がいい。 (なお、Net::XMPP2::Client; は IO::Handle;に依存)

また、同時に複数のパイプが開かれる場合があるので、 ファイルハンドルには未定義の変数をあて、Perl (5.6.0 以降) に自動的に生成してもらう。 ファイルハンドルに変数を使うことはできない。

コールバック Helper->add_watch

子プロセスから読込んだデータを親プロセスで使うには、 子プロセスの終了を検知しなければならない。

AnyEvent で子プロセスの終了を検知したり、 ファイルハンドラの読み込みからコールバックしたりすることもできるが、 今回は Gtk の Helper->add_watch で ファイルハンドラの読み込みからのコールバックを使った。 サンプルあり。

親プロセスで、Helper->add_watch のセットをしておけば、 子プロセスの終了を待たず (たぶん)、データがある程度流れて来次第、 親プロセスでそのデータを随時処理できるようだ。 子プロセスでパイプを close されると、そこでデータの読み込みを終了する。

もっと簡単な方法

……と言うように実装してしばらくしてから、 Re: forking an external process: msg#00022 というそのものの記事を見つけた。 LWP::UserAgent でサブルーチンのリファレンスを引数として渡し、 その中で Gtk->main_iteration while Gtk->events_pending; を呼ぶという方法だ。 とても賢い。ちゃんと試してないが大抵のところこれで十分だろう。 気づくのが遅かった。

追記: いろいろ書いたけど、結局のところモジュール依存を気にしなければ、 AnyEvent-HTTP を使えば超簡単。お勧め。 (2009/4/18)

2008/05/21 (Wed) 01:28 | タグ: computer


同じカテゴリの最新記事

  1. GNOME 写真フレーム
  2. PyGTK でのバックグラウンド動作
  3. gnome-terminal の文字幅問題
  4. F-Spot の日本語メッセージカタログ
  5. Twitim: Twitter 専用 XMPP クライアント