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.
no subject
Date: 2013-11-15 09:20 (UTC)no subject
Date: 2013-11-15 12:21 (UTC)no subject
Date: 2013-11-16 00:14 (UTC)Выдаёт:
func: new iteration started
func: iteration finished
func: new iteration started
Thread 1 terminated abnormally: panic: MUTEX_LOCK (22) [shared.xs:200] at ./panic.pl line 21.
no subject
Date: 2013-11-16 00:34 (UTC)--- panic.pl 2013-11-16 07:11:49.000000000 +0700 +++ panic2.pl 2013-11-16 07:31:53.000000000 +0700 @@ -8,9 +8,9 @@ $|=1; our $db :shared; +our $new :shared; sub func() { - my $new; while (1) { print STDERR "func: new iteration started\n";