3

mod_perl で簡単なタイムゾーン計算を行う必要があります。DateTime はオプションではありません。私がしなければならないことは、$ENV{TZ} を設定し、localtime と POSIX::mktime を使用することで簡単に達成できますが、スレッド化された MPM の下では、一度に 1 つのスレッドだけが環境をいじることを確認する必要があります。(localtimeなどの他の用途については気にしません。)

環境へのアクセスをシリアル化する (非マーシャリングの意味で) ミューテックスまたはその他のロック戦略を使用するにはどうすればよいですか? 私が見たドキュメントでは、この用途のためだけにミューテックスを作成する方法が十分に説明されていません。一般的にミューテックスを作成する方法について、私が理解していないことがあるかもしれません。

更新: はい、Env::C を使用して TZ を設定する必要があることを認識しています。

4

3 に答える 3

3

この問題のため、mod_perl 2 は実際には mod_perl 1 とは異なる方法で %ENV ハッシュを処理します。mod_perl 1 では、%ENV は環境構造体に直接関連付けられていたため、%ENV を変更すると環境が変更されました。mod_perl 2 では、%ENV ハッシュは Environ から取り込まれますが、変更は返されません。

これは、特にスレッド化された環境で、タイムゾーンを調整するために $ENV{TZ} をいじることができなくなったことを意味します。Apache2::Localtimeモジュールは、(Env::C を使用することにより) スレッド化されていない場合でも機能しますが、スレッド化された MPM で実行する場合は悪いニュースになります。

mod_perl ソース (src/modules/perl/modperl_env.c) には、この問題に関するいくつかのコメントがあります。

/* * XXX: what we do here might change:
 *      - make it optional for %ENV to be tied to r->subprocess_env
 *      - make it possible to modify environ
 *      - we could allow modification of environ if mpm isn't threaded
 *      - we could allow modification of environ if variable isn't a CGI
 *        variable (still could cause problems)
 */
/*
 * problems we are trying to solve:
 *      - environ is shared between threads
 *          + Perl does not serialize access to environ
 *          + even if it did, CGI variables cannot be shared between threads!
 * problems we create by trying to solve above problems:
 *      - a forked process will not inherit the current %ENV
 *      - C libraries might rely on environ, e.g. DBD::Oracle
 */
于 2008-09-24T14:01:58.593 に答える
3

(PerlMonks で言ったことを繰り返します...)

BEGIN {
    my $mutex;

    sub that {
        $mutex ||= APR::ThreadMutex->new( $r->pool() );
        $mutex->lock();

        $ENV{TZ}= ...;
        ...

        $mutex->unlock();
    }
}

しかしもちろん、1 回限りのハックを除いて、lock() は c'tor で発生し、unlock() は d'tor で発生する必要があります。

Update: Note that there is a race condition in how $mutex is initialized in the subroutine (two threads could call that() for the first time nearly simultaneously). You'd most likely want to initialize $mutex before (additional) threads are created but I'm unclear on the details on the 'worker' Apache MPM and how you would accomplish that easily. If there is some code that gets run "early", simply calling that() from there would eliminate the race.

Which all suggests a much safer interface to APR::ThreadMutex:

BEGIN {
    my $mutex;

    sub that {
        my $autoLock= APR::ThreadMutex->autoLock( \$mutex );
        ...
        # Mutex automatically released when $autoLock destroyed
    }
}

Note that autoLock() getting a reference to undef would cause it to use a mutex to prevent a race when it initializes $mutex.

于 2008-09-24T05:18:54.857 に答える
1

Apache 1.3 を使用している場合は、ミューテックスに頼る必要はありません。Apache 1.3 は多数のワーカー プロセスを生成し、各ワーカーは単一のスレッドを実行します。この場合、次のように記述できます。

{
    local $ENV{TZ} = whatever_I_need_it_to_be();

    # Do calculations here.
}

で変数を変更するlocalと、ブロックの最後で以前の値に戻りますが、そのブロック内から行われたサブルーチン呼び出しには引き続き渡されます。それはほぼ確実にあなたが望むものです。各プロセスには独自の独立した環境があるため、この手法を使用して他のプロセスの環境を変更することはありません。

Apache 2 の場合、フォークとスレッドに関してどのモデルを使用しているかはわかりません。プロセスをフォークし、それぞれに 1 つのスレッドを持つという同じアプローチを維持する場合は、問題ありません。

apache 2 が誠実な本物のスレッドを使用している場合、それは私の詳細な知識の範囲外ですが、別の素敵なスタックオーバーフロー担当者が支援を提供してくれることを願っています。

どうぞよろしくお願いいたします。

Paul
于 2008-09-24T02:08:12.803 に答える