無料Wikiサービス | デモページ
Linuxなどのメモ書き

mod_perlハンドラを書く


このテキストは

このテキストはmod_perl2.0ドキュメントの"Writing mod_perl Handlers and Scripts"(http://perl.apache.org/docs/2.0/user/coding/coding.html)の和訳です。

mod_perlハンドラとスクリプトを書く

目次

説明
前提
メソッドが有効な場所
Techniques
メソッドハンドラ
クリーンアップ
役に立つツール
環境変数
スレッド化MPMか否か
MPM固有のコードを書く
Code Developing Nuances
修正されたモジュールの自動リロード
Apacheとの統合の問題
HTTPレスポンスヘッダ
HTTPレスポンスBodyの送信
シグナルハンドラの使用
mod_perl環境でのPerlの仕様
BEGINブロック
CHECK,INITブロック
ENDブロック
リクエスト毎のグローバル変数
exit
ModPerl::Registryのハンドラ
背後で起きていること
$rオブジェクトの取得
mod_perl環境下でのスレッドコーディングの問題
スレッド環境の問題
スレッドを効果的に使う
共有変数
Maintainers
Authors

説明

この章ではmod_perlのコーディングの詳細、通常のPerlコーディングとの違いを扱います。その他のほとんどのPerlコーディングに関する情報はperlのmanページや書籍で取り扱われています。

前提

原文なし

メソッドが有効な場所

mod_perl 2.0では多くのモジュールに跨ってメソッドが存在します。これらのメソッドを使うためにメソッドを含むモジュールは最初にロードしておかないといけません。そうでないと、mod_perlは「メソッドを見つけられない」とエラーにします。どのモジュールが必要かを探すにはModPerl::MethodLookup モジュールが使えます。

Techniques

メソッドハンドラ

関数ハンドラに加えてメソッドハンドラを使うことができます。メソッドハンドラは継承のメリットを生かしたコードを書きたい場合に便利です。mod_perl2のメソッドとしてハンドラを作る場合、method属性を使ってください。

属性の詳細についてはPerlのmanページを参照してください(perldoc attributes)。

例:

  package Bird::Eagle;
  @ISA = qw(Bird);

  sub handler : method {
      my ($class_or_object, $r) = @_;
      ...;
  }

  sub new { bless {}, __PACKAGE__ }

そして、これを以下のようにして登録します。

  PerlResponseHandler Bird::Eagle

mod_perlはハンドラがmethod属性を持っている場合は、2つの引数をハンドラに渡します。上記のコードにもあるようにオブジェクトもしくはクラス名(どのように呼び出されたかに依存します)とRequestオブジェクトです。

以下のようにClass->methodのような形式が使われた場合は、

  PerlResponseHandler Bird::Eagle->handler;

method属性は必要ありません。上の設定例ではhandler()メソッドはクラス(静的)メソッドとして呼び出されます。

メソッドを呼び出すのにオブジェクトを使うこともできます。例えば、

  <Perl>
      use Bird::Eagle;
      $Bird::Global::object = Bird::Eagle->new();
  </Perl>
  ...
  PerlResponseHandler $Bird::Global::object->handler

この例では、hanlder()メソッドはグローバルオブジェクト$Bird::Global::objectのインスタンスメソッドとして呼び出されます。

クリーンアップ

さまざまなフェーズの終わりで発生するクリーンアップ処理をアレンジできます。これを行うのにENDブロックは使えません。なぜなら、ENDブロックはインタプリタが終了するまで実行されないからです(Registryハンドラは例外です)。

モジュール作成者は各HTTPリクエストの後にクリーンアップ処理が必要な場合は、PerlCleanupHandlerを使うべきです。

その他のタイミングでクリーンアップ処理を行う必要がある場合は、プールオブジェクトのcleanup_registerメソッドでクリーンアップコールバックを登録することができます。使用例をいくつか示します。

サーバーのシャットダウンやリスタート時に何か行いたい場合は、startup.plでserver_shutdown_cleanup_register()で登録したクリーンアップハンドラを使ってください。

  #PerlPostConfigRequire startup.pl
  use Apache2::ServerUtil ();
  use APR::Pool ();

  warn "parent pid is $$\n";
  Apache2::ServerUtil::server_shutdown_cleanup_register((\&cleanup);
  sub cleanup { warn "server cleanup in $$\n" }

この方法は、サーバーが停止したり、再起動する時に行うべきサーバー全体のクリーンアップ処理を行うのに便利です。

接続フェーズの終わりにクリーンアップを行う場合は、コネクションプールオブジェクトにクリーンアップコールバックを割り当てます。

  use Apache2::Connection ();
  use APR::Pool ();

  my $pool = $c->pool;
  $pool->cleanup_register(\&my_cleanup);
  sub my_cleanup { ... }

あなた自身のプールオブジェクトを作成してコールバックを登録することもできます。これはオブジェクトが破壊された時に呼び出されます。

  use APR::Pool ();

  {
      my @args = 1..3;
      my $pool = APR::Pool->new;
      $pool->cleanup_register(\&cleanup, \@args);
  }

  sub cleanup {
      my @args = @{ +shift };
      warn "cleanup was called with args: @args";
  }

この例ではクリーンアップコールバックは$poolがスコープの外に出て破壊された時に呼び出されます。これはオブジェクト指向のDESTROYメソッドに非常に似ています。

役に立つツール

環境変数

mod_perlは次の環境変数を設定します。

  • $ENV{MOD_PERL} - mod_perlのバージョンが設定されます

例:

  mod_perl/2.000002

$ENV{MOD_PERL}が存在しなければ、たぶんmod_perl配下で動作していません。

  die "I refuse to work without mod_perl!" unless exists $ENV{MOD_PERL};

どのバージョンが使われているのかチェックするには、次のテクニックを使うとよいです。

  use mod_perl;
  use constant MP2 => ( exists $ENV{MOD_PERL_API_VERSION} and 
                        $ENV{MOD_PERL_API_VERSION} >= 2 ); 

  # die "I want mod_perl 2.0!" unless MP2;

mod_perlは次の環境変数をエクスポートします(それらが設定されていれば)。

  • PATH - 実行可能ファイルのパス
  • TZ - タイムゾーン

これらの環境変数は%ENVでアクセスできます。

スレッド化MPMか否か

実行環境がスレッド化されたMPMかそうでないかでコードが異る動作をする必要があるならApache2::MPM->is_threadedクラスメソッドが使えます。

例:

  use Apache2::MPM ();
  if (Apache2::MPM->is_threaded) {
      require APR::OS;
      my $tid = APR::OS::current_thread_id();
      print "current thread id: $tid (pid: $$)";
  }
  else {
      print "current process id: $$";
  }

このコードはスレッド化されたMPM配下ではカレントスレッドIDを表示します。そうでなければプロセスIDを表示します。

MPM固有のコードを書く

あなたがCPANモジュールを書くなら、全てのMPMで動作しないコードを書くのはまずい考えです。開発者は全てのMPMで動作するコードを書くよう努力すべきです。異るMPM環境で異ることを行うのはまったく立派なことです。

あなたがCPANモジュールを開発しないなら、特定のMPMで動作すればあなたのプロジェクトにとって十分でしょう。

  use Apache2::MPM ();
  my $mpm = lc Apache2::MPM->show;
  if ($mpm eq 'prefork') {
      # prefork-specific code
  }
  elsif ($mpm eq 'worker') {
      # worker-specific code
  }
  elsif ($mpm eq 'winnt') {
      # winnt-specific code
  }
  else {
      # others...
  }

Code Developing Nuances

修正されたモジュールの自動リロード

META: need to port Apache2::Reload notes from the guide here. but the gist is:

  PerlModule Apache2::Reload
  PerlInitHandler Apache2::Reload
  #PerlPreConnectionHandler Apache2::Reload
  PerlSetVar ReloadAll Off
  PerlSetVar ReloadModules "ModPerl::* Apache2::*"

以下のハンドラを使ってください。

  PerlInitHandler Apache2::Reload
HTTPプロトコルハンドラをデバッグしたいなら、以下のようにしてください。
  PerlPreConnectionHandler Apache2::Reload

我々が自分達のモジュールを以下のような形式にする場合の注意です。

  package Apache2::Whatever;

  use strict;
  use warnings FATAL => 'all';

FATAL => 'all' は全ての警告をfatalエラーとして上げます。Apache2::Whateverが変更されてApache2::Reloadによって再読み込みされた時、リクエストは中断されてしまいます。ですから、もしあなたがこの非常に健全な方法にしたがってApache2::Reloadを使いたいなら以下のようにエラーチェックの厳密さを変更してください。

  use warnings FATAL => 'all';
  no warnings 'redefine';

redifne 警告を取得したいが、non-fatalにレベルを落とす場合は次のようにしてできます。

  use warnings FATAL => 'all';
  no warnings 'redefine';
  use warnings 'redefine';

Perl 5.8.0なら1行で全て行えます。

  use warnings FATAL => 'all', NONFATAL => 'redefine';

もしあなたのコードが古いバージョンのPerlで使われるかもしれないのなら、この新しいは使わないほうがよいでしょう。

さらなる情報はperllexwarn manページを参照してください。

Apacheとの統合の問題

以下ではmod_perl開発者に関係するApacheの振る舞いの詳細について議論していきます。

HTTPレスポンスヘッダ

HTTPレスポンスヘッダの生成

HTTPレスポンスヘッダを生成する最もよい方法はmod_perl APIを使うことです。いくつかの共通のヘッダには専用のメソッドがあります。その他のものも、headers_outテーブルを直接操作することで設定できます。

例えば、Content-typeヘッダを設定する場合は、$r->content_typeを呼び出すべきです。

  use Apache2::RequestRec ();
  $r->content_type('text/html');

カスタムヘッダMy-Headerを設定する場合は、以下のようにしてください。

  use Apache2::RequestRec ();
  use APR::Table;
  $r->headers_out->set(My-Header => "SomeValue");

もし、registryスクリプトの中であれば、Apache2::RequestRecオブジェクトにまだアクセスできます。

レスポンスヘッダを出力することによってヘッダを作成するもっと遅い方法を採ることもできます。この方法はPerlOptions +ParseHeadersが有効な場合のみ動作します。

   print "Content-type: text/html\n";
   print "My-Header: SomeValue\n";
   print "\n";

この方法はApacheがヘッダを識別するためテキストをパースする必要があるので遅くなります。
またいくつかの制限があります(これから議論します)。

このアプローチでは、STDOUTファイルハンドルがprint後にデータをフラッシュしないようになっていることを確認しなければなりません(これはPerlの特殊変数$|に設定されています)。STDOUTが現在select()されており$|がそれに影響するものと仮定しています。

例えばこのコードは動作しません。

   local $| = 1;
   print "Content-type: text/html\n";
   print "My-Header: SomeValue\n";
   print "\n";

$|が真だと最初のprint()呼び出し後、すぐにデータがフラッシュされます。データは内部のHTTPヘッダパーサーに送られます。そしてヘッダが"\n\n"で終わっていないように見えるのでエラーになります。解決方法としてはSTDOUTをすぐにフラッシュさせないようにする方法があります。

   local $| = 0;
   print "Content-type: text/html\n";
   print "My-Header: SomeValue\n";
   print "\n";

変更をlocal()化していることに気をつけてください。これだと、他のコードに影響しません。

もし、あなたが1行づつヘッダを送信しそれらの合計長が8kを越えると、ヘッダパーサーの問題にまたぶつかるでしょう。mod_perlは8kバッファがいっぱいになるとデータをフラッシュするからです。この場合の解決法はヘッダを1行づつ出力しないようにすることです。変数にヘッダを格納して全体を一気に出力します。

mod_cgiを使う場合はこれらの問題は関係ありません。Perlによるフラッシュは無視されるからです。mod_cgiは外部プロセスへのパイプをオープンしプロセスから送られてきた出力を読み取るだけです。

この節の始めで説明したように、$rを使ってヘッダを設定するなら、これらの問題に遭遇することはありません。

最後にApacheにヘッダを送らせず、あなたが自分でヘッダ(non-parsed headers handlers)を送信したい場合は、$r->assbackwards メソッドを使ってください。スクリプト名がnph-で始まる場合は、registryハンドラはこのように動作することに注意してください。

HTTPレスポンスヘッダの強制出力

Apache 2.0はHTTPレスポンスヘッダの送信を強制するメソッドを提供しません(Apache 1.3ではsend_http_header()が相当)。HTTPレスポンスヘッダはレスポンスBodyの最初のビットを見つけるとヘッダを作成するCore outputフィルタによりすぐに送信されます。レスポンスハンドラがボディデータの最初の部分を送信するときに、mod_perlの内部バッファやいくつかのoutputフィルタによりキャッシュされたりするかもしれません。レスポンスハンドラはレスポンスの送信にかかわっている全コンポーネントにデータ送信を伝えるために出力をフラッシュする必要があります。

例えば、もしハンドラが比較的時間のかかる処理(遅いDBの検索とか)を行う必要があり、すぐにクライアントが何も受信しないとタイムアウトするかもしれない場合、ハンドラの始めにContent-Typeヘッダを設定してすぐにフラッシュしたいかもしれません。

  sub handler {
      my $r = shift;
      $r->content_type('text/html');
      $r->rflush; # send the headers out

      $r->print(long_operation());
      return Apache2::Const::OK;
  }

これが動作しないなら、サードパーティ製のoutputフィルタが設定されていないか確認してください。Improperly written filter はデータをフラッシュするのにコマンドを無視するかもしれません。

HTTPレスポンスBodyの送信

mod_perl 2.0ではレスポンスBodyはレスポンスフェーズの間のみ送ることができます。もっと前のフェーズで送信しようとすると、error_logファイルにログが出力されて失敗します。

これは、Apache 2.0のHTTPアーキテクチャによるものです。レスポンスフェーズの前ではHTTPレスポンスフィルタ設定されていないのが問題の1つです。

シグナルハンドラの使用

サードパーティのApache 2 モジュールはシグナルに頼ったコードを使うのを避けるべきです。
これは、シグナルの使用は典型的にスレッドセーフでないのと、シグナルに頼ったモジュールはポータビリティがないかもしれません。あるシグナルはスレッド化されていないMPMでしか動作しないかもしれません。例えばalarm()はprefork MPMで使うことができますが、他のMPM環境化では動作しないでしょう。さらにApache開発者は現在たまたま動作しているシグナルが将来のApacheリリースでも動作することは保証しません。だから、あなた自身の責任で使ってください。

スレッドでも動作するようにシグナルを使ったコードを修正できるとよいです。例えば、もし長時間動作する可能性のあるI/Oをトラップするのにalarm()を使っていたならselect/pollを使うようにI/Oロジックを修正することができます。もしくはAPR I/Oを使っているならAPRパイプ/ソケットにタイムアウトを設定できます。例えばUnix上のApache 1.3はブロッキングI/O呼び出しを行い、それをタイムアウトで中断するSIGALRMを送信するのを親プロセスに頼っていました。Apache 2.0ではI/O処理のタイムアウトをサポートしているAPRが使われます。だから、シグナルや他のスレッドセーフでない手法は必要ありません。

CPUタイムアウトのハンドリングはもう1つの例です。インターバルでタイムアウトを明示的にチェックするようにロジックを修正することで実現できます。

prefork MPM下でのalarm()について説明します。POSIXシグナルは動作するように見えます。しかし、Perl 5.8.xが必要です。例えば、

  use POSIX qw(SIGALRM);
  my $mask      = POSIX::SigSet->new( SIGALRM );
  my $action    = POSIX::SigAction->new(sub { die "alarm" }, $mask);
  my $oldaction = POSIX::SigAction->new();
  POSIX::sigaction(SIGALRM, $action, $oldaction );
  eval {
      alarm 2;
      sleep 10 # some real code should be here
      alarm 0;
  };
  POSIX::sigaction(SIGALRM, $oldaction); # restore original
  warn "got alarm" if $@ and $@ =~ /alarm/;
詳細はこちらを参照:
http://search.cpan.org/dist/perl/ext/POSIX/POSIX.pod#POSIX::SigAction

5.6.xでは$SIG{ALRM}を使うことができました。しかしDSO modperl環境でしか動作しません。さらに5.8.0からPerlはシグナルを安全に処理するためにシグナルの発生を遅延させます。この変更は以前動作していたコードをだめにするかもしれません。詳細は以下を参照。

http://search.cpan.org/dist/perl/pod/perl58delta.pod#Safe_Signals
http://search.cpan.org/dist/perl/pod/perlipc.pod#Deferred_Signals_%28Safe_Signals%29

例えば、以下のalarmコードの場合、

  eval {
      local $SIG{ALRM} = sub { die "alarm" };
      alarm 3;
      sleep 10; # in reality some real code should be here
      alarm 0;
  };
  die "the operation was aborted" if $@ and $@ =~ /alarm/;

これは、今はもう動かないかもしれません。5.8.1以降ならプログラム実行開始後すぐに(mod_perlならstartup.pl内)、以下のように設定してシグナルの安全性をすり抜けることができます。

  $ENV{PERL_SIGNALS} = "unsafe";

この記事を書いている時点では、この次善策はMacOSXではうまくいきません。代わりにPOSIXシグナルを使わなければいけません。

詳細な情報は以下を参照してください。

http://search.cpan.org/dist/perl/pod/perl581delta.pod#Unsafe_signals_again_available
http://search.cpan.org/dist/perl/pod/perlrun.pod#PERL_SIGNALS

あなたが5.8.xを使っているのであっても、この節で説明したPOSIX APIを使う方が望ましいです。

mod_perl環境でのPerlの仕様

以下の節ではmod_perl環境でのPerlの振る舞いについて議論します。

BEGINブロック

Perlはコードをコンパイルするときに、できるだけ早くBEGINブロックを実行します。mod_perl環境でもこれは同じです。しかし、mod_perlは通常スクリプトとモジュールを一回しかコンパイルしないので、親サーバー(サーバー動作開始時)か各子プロセス(モジュールを使用する最初のリクエスト時)のどちらかでBEGINブロックは一回だけ実行されます。perlmodのmanページではBEGINブロックは一度だけ実行されて、実行されればすぐに未定義になると説明しています。これは、mod_perl環境では(例えばまだロードされていなかったなどの理由で)コードのコンパイルがたまたま発生しなければ、受信したリクエストに対してレスポンスしている間にBEGINブロックが実行されることがないことを意味しています。

require()やuse()で読み込んだモジュールやファイル内のBEGINブロックは、以下のように実行されます。

  • サーバ動作開始時に親プロセスによって読み込まれたら、一回だけ実行
  • 親プロセスによって読み込まれていなければ、各子プロセスやPerlインタプリタ毎に一回実行
  • Apache2::Reloadでモジュールが再読み込みされる場合は、各子プロセスやPerlインタプリタ毎に一回実行
  • %INCを弄った場合は、予測不能

BEGINブロックの振る舞いはModPerl::RegistryとModPerl::PerlRunとこれらのサブクラスでは異ります。

CHECK,INITブロック

CHECKとINITブロックはソースコードのコンパイルが完了して、プログラムが動作する前に実行されます。CHECKは"checkpoint","double-check"もしくは"stop"を意味します。INITは"initialization"を表します。違いはわずかで、CHECKブロックはコンパイルが終わった後に実行されます。INITはランタイムが始まる前に実行されます。(したがってperlの-c オプションはINITブロックではなくCHECKブロックを実行しています)

起動時にmod_perlが一回だけ呼び出すperl_parse()の間でのみこれらのブロックを呼び出します。スレッド化MPM環境では、これらのブロックは親のPerlインタプリタ起動の度に呼び出されます。サーバーが起動した後はCHECKとINITブロックは動くことはありません。以下のコードサンプルが動作しないのと同じ理由です。

  % perl -e 'eval qq(CHECK { print "ok\n" })'
  % perl -e 'eval qq(INIT  { print "ok\n" })'

ENDブロック

ENDブロックはインタプリタが終了する時に、できるだけ遅く実行されるとperlmod manページでは説明しています。例えばmod_cgiではENDブロックを起動の度に実行します。これは、各起動時に新しいインタプリタが実行され、リクエスト処理が完了するとkillされるからです。

mod_perl環境においてはリクエストを処理してもインタプリタは(終了するように設定されていなければ)終了しないのでサーバーがシャットダウンする時だけENDブロックが実行されます。ただそ、もっと早い時期に発生する場合もあります(例えばMaxRequestsPerChild個のリクエストを処理したのでプロセスが終了する場合)。

mod_perlはModPerl::Registry系のクラスで動作するスクリプトに特別な状態を作ります。

クリーンアップ セクションでは非Registryハンドラ用にクリーンアップをどのように扱えばよいかを説明しています。

いつでも、ENDブロックを実行するようにregistryハンドラによって内部で使われる以下のルーチンを使うことができます。

ModPerl::Global API: special_list_register, special_list_call and special_list_clear

リクエスト毎のグローバル変数

mod_perl 2.0 は2種類のSetHandlerハンドラ(modperlとperl-script)を提供します。SetHandlerディレクティブはレスポンスフェーズのハンドラに対してだけ関係することを覚えておいてください。非レスポンスフェーズには影響を及ぼしません。

  SetHandler perl-script

こうすると、いくつかのグローバル特殊変数がハンドラが呼び出される前にセーブされます。そして、あとでリストアされます。これらには次のものが含まれます。 %ENV, @INC, $/, STDOUTの $| そして END blocks 配列 (PL_endav).

  SetHandler modperl

何もリストアされません。だから、あなたはローカルの変更が他のハンドラに影響しないように全ての特殊変数を局所化するように覚えておくのを特に気を付けるべきです。

exit

通常のPerlコードではexit()はプログラムの流れを止め、Perlインタプリタを終了させるのに使います。しかし、mod_perl環境下ではPerlインタプリタを終了させることなくプログラムの流れを止める必要あります。

あなたのコードにexit()が含まれていて、exit()を使い続けても問題ないなら何もすべきではありません。mod_perlはexit()関数をプログラムのフローを止め、必要なクリーンアップ処理を行うがサーバーは終了させないようにしています。これはオーバーライドによって行われます。

  *CORE::GLOBAL::exit = \&ModPerl::Util::exit;
ですから、あなたが*CORE::GLOBAL::exitを自分で再定義して、よりよくすることができます。

インタプリタを終了させるためにCORE::exitを呼び出すことも可能です。

1つ注意はexitがevalの中で呼ばれる時です。the ModPerl::Util::exit documentationでこの状況の扱い方について説明しています。

ModPerl::Registryのハンドラ

背後で起きていること

もしあなたがCGIスクリプトtest.plを持っているなら、
  #!/usr/bin/perl
  print "Content-type: text/plain\n\n";
  print "Hello";

典型的なRegistryファミリのハンドラはこれを以下のように、

  package foo_bar_baz;
  sub handler {
      local $0 = "/full/path/to/test.pl";
  #line 1 test.pl
      #!/usr/bin/perl
      print "Content-type: text/plain\n\n";
      print "Hello";
  }

ほぼ一人前のmod_perlハンドラに変えます。唯一の違いはハンドラがステータスを返すことです。

そして以下のようにして実行します。

  foo_bar_baz::handler($r);

$rが唯一の引数としてhandler関数に渡されます。

使われたRegistryハンドラによって、パッケージ名はファイルパス、URI、それ以外から構成されます。どのようなやり方かはハンドラのドキュメントを確認してください。

$r オブジェクトの取得

背後で起きていること の説明であった$rオブジェクトは、いつもRegistryスクリプトの特殊関数handlerにただ1つの引数として渡されています。ですから、あなたは、@_にアクセスすることでこのオブジェクトを取得することができます。

  my $r = shift;
  print "Content-type: text/plain\n\n";
  print "Hello";

これは以下のようになります。

  sub handler {
      my $r = shift;
      print "Content-type: text/plain\n\n";
      print "Hello";
  }

さまざまなmod_perlメソッドを呼び出すのに$rを使うことができます。例えば以下のようにスクリプトを書き直せます。

  my $r = shift;
  $r->content_type('text/plain');
  $r->print();
あなたがコードの奥深くに入り込んで$rを取得できないならApache2->requestを使えます。

mod_perl環境下でのスレッドコーディングの問題

以下のセクションではスレッド化MPM環境下でmod_perlを動作させる時のスレッドの問題について議論します。

スレッド環境の問題

あなたのコードがスレッドセーフであること、そして同じプロセス内の全スレッドに影響を及ぼす関数を使わないようにすることだけ気を付けないといけません。

Perl5.8.0自身はスレッドセーフです。これは、push(),map(),chomp(),=,/,+=などがスレッドセーフということです。システムコールを含む処理はスレッドセーフかもしれないしそうでないかもしれません。Perl関数によって使われるCライブラリがスレッドセーフかどうかに依存します。

例えばasctime(3)の実装がスレッドセーフでない場合は、localtime()関数はスレッドセーフではありません。他の大抵問題がある関数はreaddir(), srand()などを含んでいます。

もう1つ重要な問題はいくらかの人々がスレッドローカルなものとして考えているものです。1つのスレッドで実行されたある関数がプロセス全体に影響を及ぼして、プロセス内の
他の全スレッドに影響します。例えば、もしあるスレッドでchdir()を使ったら、他の全てのスレッドでもchdir()したスレッドのカレントディレクトリが見えます。同じ様な効果のある他の関数はumask(), chroot()などを含んでいます。現在この問題に対する解決法はありません。あなたは、あなたのコードの中からこれらの関数を見つけ、この問題の影響を受けない別の方法に置き換えなければなりません。

さらなる情報はperlthrtut (http://perldoc.perl.org/perlthrtut.html) manページを参照してください。

スレッドを効果的に使う

これはmod_perl 2.0には全く関係ありません。スレッド化MPM mod_perl環境であなたのコードを正しく動作させるために、あなたはPerlスレッドについてはスレッド環境の問題以外にあまり知る必要はありません。

あなたが、自分のスレッドを生成したいなら、まずはperlthrtut, threads(http://search.cpan.org/search?query=threads) とthreads::shared (http://search.cpan.org/search?query=threads%3A%3Ashared)manページを読んでPerlの新しいithreadsモデルがどのように動作するのか勉強してください。

Perl ithreadsで正しく動作するようにPure Perlモジュールをportする方法を説明した記事をArtur Bergmanが書いています。chdir()と共有されたプロセスデータ構造に頼った他の関数の問題が議論されています。

http://www.perl.com/lpt/a/2002/06/11/threads.html

共有変数

グローバル変数はそれらを生成したインタプリタ内でのみグローバルです。他のスレッドの他のインタプリタはこの変数にアクセスできません。ですが、threads::shared::share()関数を使って同じプロセス内のスレッド間で変数を共有させることもできます。変数を生成するときにshared属性をつけることで新しい変数を共有することができます。この機能はthreads::shared(http://search.cpan.org/search?query=threads%3A%3Ashared) manページに記述されています。

Maintainers

Maintainer is the person(s) you should contact with updates, corrections and patches.

Authors

Only the major authors are listed above. For contributors see the Changes file.


最終更新 2007/05/25 20:04:56 - kztomita
(2007/05/25 17:29:38 作成)