Внутрипроцессное согласование в mod_perl под рабочим MPM - PullRequest
3 голосов
/ 24 сентября 2008

Мне нужно сделать простой расчет часового пояса в mod_perl. DateTime не вариант. То, что мне нужно сделать, легко сделать, установив $ ENV {TZ} и используя localtime и POSIX :: mktime, но в многопоточном MPM мне нужно было бы убедиться, что только один поток за раз пересекался со средой. (Меня не интересует другое использование местного времени и т. Д.)

Как я могу использовать мьютекс или другую стратегию блокировки для сериализации (в смысле не маршалинга) доступа к среде? документы , на которые я смотрел, недостаточно хорошо объясняют, как я мог бы создать мьютекс только для этого использования. Может быть, я просто не понимаю, как вы вообще создаете мьютексы.

Обновление: да, я знаю о необходимости использования Env :: C для установки TZ.

Ответы [ 3 ]

3 голосов
/ 24 сентября 2008

(повторяя то, что я сказал в PerlMonks ...)

BEGIN {
    my $mutex;

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

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

        $mutex->unlock();
    }
}

Но, конечно, lock () должна происходить в c'tor, а unlock () должна происходить в d'tor, за исключением одноразовых хаков.

Обновление: обратите внимание, что существует условие гонки в том, как $ mutex инициализируется в подпрограмме (два потока могут вызывать это () в первый раз почти одновременно). Скорее всего, вы захотите инициализировать $ mutex перед созданием (дополнительных) потоков, но мне неясно, как обстоят дела с «рабочим» 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.

3 голосов
/ 24 сентября 2008

Из-за этой проблемы mod_perl 2 фактически работает с хешем% ENV иначе, чем mod_perl 1. В mod_perl 1% ENV был напрямую связан со структурой среды, поэтому изменение% ENV изменило среду. В mod_perl 2 хеш% ENV заполняется из среды, но изменения не передаются обратно.

Это означает, что вы больше не можете использовать $ 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
 */
1 голос
/ 24 сентября 2008

Если вы используете apache 1.3, вам не нужно прибегать к мьютексам. Apache 1.3 порождает несколько рабочих процессов, и каждый рабочий выполняет один поток. В этом случае вы можете написать:

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

    # Do calculations here.
}

Изменение переменной с помощью local означает, что она возвращается к предыдущему значению в конце блока, но все еще передается в любые вызовы подпрограммы, сделанные из этого блока. Это почти наверняка то, что вы хотите. Поскольку каждый процесс имеет свою собственную независимую среду, вы не будете изменять среду других процессов, используя эту технику.

Для apache 2 я не знаю, какую модель он использует в отношении вилок и потоков. Если он придерживается того же подхода, что и для процессов, и для каждого потока по одному, то все в порядке.

Если apache 2 использует честные и добрые реальные потоки, то это не входит в сферу моих подробных знаний, но я надеюсь, что другой прекрасный стековый поток может помочь.

Всего самого наилучшего,

Paul
...