代码之家  ›  专栏  ›  技术社区  ›  ysth

worker-mpm下mod_-perl的进程内协调

  •  3
  • ysth  · 技术社区  · 16 年前

    我需要用mod_perl做一些简单的时区计算。日期时间不是一个选项。我需要做的是通过设置$env{tz}并使用localtime和posix::mktime来轻松完成,但是在线程化的mpm下,我需要确保一次只有一个线程在破坏环境。(我不关心本地时间的其他用途等)

    如何使用互斥锁或其他锁定策略序列化(在非封送处理的意义上)对环境的访问?这个 docs 我没有很好地解释如何为这种用途创建互斥锁。也许有一些事情我只是没有得到关于如何创建互斥的一般。

    更新:是的,我知道需要使用env::c设置tz。

    3 回复  |  直到 16 年前
        1
  •  3
  •   tye    16 年前

    (重复我在帕尔蒙克斯说的话……)

    BEGIN {
        my $mutex;
    
        sub that {
            $mutex ||= APR::ThreadMutex->new( $r->pool() );
            $mutex->lock();
    
            $ENV{TZ}= ...;
            ...
    
            $mutex->unlock();
        }
    }
    

    但是,当然,lock()应该在c'tor中发生,unlock()应该在d'tor中发生,除了一次性的黑客攻击。

    update:请注意,在子例程中初始化$mutex时有一个竞争条件(两个线程可以几乎同时第一次调用that())。您很可能希望在创建(额外的)线程之前初始化$mutex,但我不清楚“worker”apache mpm的详细信息以及如何轻松地实现这一点。如果有一些代码“提前”运行,只需从那里调用that()就可以消除竞争。

    这都表明apr::threadmutex有一个更安全的接口:

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

    注意autolock()获取对undef的引用将导致它在初始化$mutex时使用互斥锁来防止竞争。

        2
  •  3
  •   Michael Cramer    16 年前

    由于这个问题,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/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
     */
    
        3
  •  1
  •   Ian    16 年前

    如果您使用的是Apache1.3,那么就不需要使用互斥锁。Apache1.3产生了许多工作进程,每个工作进程执行一个线程。在这种情况下,您可以编写:

    {
        local $ENV{TZ} = whatever_I_need_it_to_be();
    
        # Do calculations here.
    }
    

    将变量更改为 local 意味着它将返回到块末尾的上一个值,但仍将传递到从该块内部进行的任何子例程调用中。几乎可以肯定这是你想要的。由于每个进程都有自己的独立环境,因此您不会使用此技术更改其他进程的环境。

    对于Apache2,我不知道它对fork和线程使用什么模型。如果它保持了分叉进程和每个进程有一个线程的相同方法,那么就可以了。

    如果Apache2使用诚实到善良的真实线程,那么这超出了我的详细知识范围,但是我希望另一个可爱的StackOverflow人员能够提供帮助。

    一切都很好,

    Paul