perl & panic: MUTEX_LOCK
2013-11-15 14:31perl-threaded-5.14.4 (собран с useithreads=define, usemultiplicity=define).
Код такого вида:
#!/usr/bin/perl
use threads;
use threads::shared;
use strict;
use warnings;
our $db :shared;
sub func() {
my $new;
... # формируем новые данные
{ # пытаемся обновить $db, удерживая блокировку
lock($db);
$db = $new;
$new = undef;
}
}Такой код проходит все проверки синтаксиса, но во время работы нить, выполняющая func() второй раз, аварийно завершает работу на строке $db = $newlock($db) с диагностикой panic: MUTEX_LOCK (22) [shared.xs:200].
Ошибка 22 это EINVAL. В потрохах perl есть dist/threads-shared/shared.xs и в нём функция recursive_lock_release(pTHX_ recursive_lock_t *lock), которая зовёт MUTEX_LOCK(&lock->mutex) - макрос, который выкидывает этот panic, если неуспешно завершается системная функция pthread_mutex_lock() из POSIX Threads Library (libpthread, -lpthread). А она возвращает EINVAL, если переданный мутекс равен THR_MUTEX_DESTROYED.
Выходит, переписывание скаляра новым значением при удерживании блокировки разрушает мутекс. Решение было очевидным: завести под блокировку отдельный скаляр $dblock и при разграничении доступа к $db лочить $dblock.
Update: test-case.