2008-09-23 40 views
3

我需要在mod_perl中進行一些簡單的時區計算。 DateTime不是一個選項。我需要做的是通過設置$ ENV {TZ}並使用localtime和POSIX :: mktime輕鬆完成,但是在線程化的MPM下,我需要確保一次只有一個線程正在與環境混合。 (我不關心本地時間的其他用途等)工人MPM下的mod_perl中的進程內協調

如何使用互斥鎖或其他鎖定策略來序列化(在非編組意義上)訪問環境?我看過的docs沒有解釋得足夠好,我將如何爲此用途創建一個互斥鎖。也許有一些我一般都沒有想到如何創建互斥鎖。

更新:是的,我知道需要使用Env :: C來設置TZ。

回答

1

如果你使用的是Apache 1.3,那麼你不需要求助於互斥體。 Apache 1.3產生了許多工作進程,每個工作者都執行一個線程。在這種情況下,你可以寫:

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

    # Do calculations here. 
} 

改變變量與local意味着它將恢復爲在塊結束的前值,但仍傳遞到從該塊內的任何子程序調用。這幾乎可以肯定你想要什麼。由於每個進程都有自己獨立的環境,因此您不會使用這種技術改變其他進程的環境。

對於apache 2,我不知道它使用什麼模型關於分支和線程。如果它保持相同的方法來分離進程並且每個線程都有一個線程,那麼你很好。

如果apache 2使用誠實善良真正的線程,那麼這是在我的詳細知識領域之外,但我希望另一個可愛的stackoverflow人可以提供幫助。

一切順利,

Paul 
+0

的Apache 2提供了多個分叉/線程模型稱爲MPM的。我正在使用worker MPM,該進程使用多個進程和多個線程。像Apache 1那樣工作的MPM被稱爲prefork。 – ysth 2008-09-24 03:24:23

3

(重複我說了在PerlMonks ...)

BEGIN { 
    my $mutex; 

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

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

     $mutex->unlock(); 
    } 
} 

但是,當然,鎖定()應該在c'tor發生和unlock()應該在除了一次性黑客攻擊之外發生。

更新:請注意,在子程序中如何初始化$ mutex存在爭用條件(兩個線程幾乎可以同時首次調用那個())。你很可能想在創建線程之前初始化$ mutex,但我不清楚'worker'Apache MPM的細節以及你如何輕鬆完成。如果有一些代碼「早」運行,只需從那裏調用()就可以消除競爭。

這一切都表明一個更安全的接口APR :: ThreadMutex:

BEGIN { 
    my $mutex; 

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

注意,自動鎖定()獲取到民主基金的引用會導致它使用一個互斥體,以防止種族初始化時$互斥。

+0

在mod_perl中設置$ ENV {TZ}將無法在Apache 2中工作。更改不會反映回C環境,這意味着它們不會影響localtime等輸出。 – 2008-09-24 14:02:58

3

由於這個問題,mod_perl 2實際上處理%ENV哈希的方式與mod_perl 1不同。在mod_perl中1%ENV直接與環境結構綁定,所以更改%ENV改變了環境。在mod_perl 2中,%ENV散列從environ填充,但不會傳回更改。

這意味着您不能再使用$ ENV {TZ}來調整時區 - 特別是在線程環境中。 Apache2::Localtime模塊將使它適用於非線程的情況(通過使用Env :: C),但在線程MPM中運行時將會是個壞消息。

中有關於這一問題的mod_perl的源(SRC /模塊/的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 
*/