我需要在mod_perl中进行一些简单的时区计算。 DateTime不是一个选项。我需要做的是通过设置$ ENV {TZ}并使用localtime和POSIX :: mktime轻松完成,但在线程MPM下,我需要确保一次只有一个线程与环境混淆。 (我不关心本地时间的其他用途等)。
如何使用互斥锁或其他锁定策略来序列化(在非编组意义上)对环境的访问?我看过的docs并不能很好地解释如何为这个用途创建一个互斥锁。也许有些事情我只是不知道如何创建互斥体。
更新:是的,我知道需要使用Env :: C来设置TZ。
答案 0 :(得分:3)
(重复我在PerlMonks上所说的话......)
BEGIN {
my $mutex;
sub that {
$mutex ||= APR::ThreadMutex->new( $r->pool() );
$mutex->lock();
$ENV{TZ}= ...;
...
$mutex->unlock();
}
}
但是,当然,lock()应该发生在c'tor中并且unlock()应该发生在de tor中,除了一次性黑客攻击。
更新:请注意,在子例程中如何初始化$ mutex存在竞争条件(两个线程几乎可以同时第一次调用this())。您很可能希望在创建(附加)线程之前初始化$ mutex,但我不清楚'worker'Apache MPM的详细信息以及如何轻松实现这一点。如果有一些代码可以“提前”运行,只需从那里调用那个()就可以消除竞争。
所有这些都暗示了一个更安全的APR :: ThreadMutex接口:
BEGIN {
my $mutex;
sub that {
my $autoLock= APR::ThreadMutex->autoLock( \$mutex );
...
# Mutex automatically released when $autoLock destroyed
}
}
请注意,autoLock()获取对undef的引用会导致它在初始化$ mutex时使用互斥锁来阻止竞争。
答案 1 :(得分: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
*/
答案 2 :(得分: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