LINUX.ORG.RU

Can't locate object method «tid» via package «threads»

 ,


1

2

Я даже не знаю как правильно задать вопрос...
Есть система, написанная на AnyEvent::HTTP. При ошибках соединения кроме собственно ошибки пишет «Can't locate object method „tid“ via package „threads“ at /usr/share/perl/5.18/XSLoader.pm line 92.». Гугление сказало, что это как-то связано с $SIG{__DIE__}, и действительно, в одном месте он переопределяется. То есть если убрать его переопределение, странная ошибка не возникает. Оттуда же, из гугления, я понял, что нужно этот сигнал то ли как-то в более правильном месте прописать, то ли более правильным образом...

★★★★★

Ты заюзал use threads, надеясь, что он будет работать с кодом от Марка Леманна? =)) Забудь про threads, выкинь их нафиг, либо используй модули на блокировках. Читай до просветления.

Также желательно пример/кусок кода: все «юзы» и место, на котором все валится.

gh0stwizard ★★★★★
()
Последнее исправление: gh0stwizard (всего исправлений: 2)
Ответ на: комментарий от gh0stwizard

Нет, я его не использовал. Я так понял, его использует где-то внтури себя AnyEvent. Наверное.
Валится, точнее пишет вот это странное сообщение, система в процедуре, которой определён $SIG{__DIE__}. Валится она сама по себе - проблемы с сертификатом, соединение не устанавливается, оно помирает, die хватается мною - и тут ВНЕЗАПНО.

К AnyEvent никаких доп. настроек, какой механизм использовать, не применяется.

Debian, testing.

Xellos ★★★★★
() автор топика
Последнее исправление: Xellos (всего исправлений: 2)
Ответ на: комментарий от Xellos

Я так понял, его использует где-то внтури себя AnyEvent.

AnyEvent нигде не использует threads.

Валится, точнее пишет вот это странное сообщение, система в процедуре, которой определён $SIG{__DIE__}.

Из твоих слов вообще неясно где именно. Ни xsloader, ни anyevent::http вообще не содержат никаких переопределений для $SIG{__DIE__}. Вывод участка кода в студию.

gh0stwizard ★★★★★
()
Ответ на: комментарий от gh0stwizard

Я переопределяю $SIG{__DIE__}. В своём коде.
Вывести код не могу, могу порезать и показать «эквивалентный», но лучше опишу словами.

Есть perl-скрипт. Он использует AnyEvent и по таймеру запускает процедуры из модуля1. В модуле1 переопределён $SIG{__DIE__}. Некоторые процедуры из модуля1 вызывают процедуру из модуля2, которая вызывает AnyEvent::HTTP::http_post. В случае если соединение установить не удаётся (конкретно - ошибка сертификата), http_post помирает. Вызывается $SIG{__DIE__}, который вызывает одно, другое, третье и в конце концов вызывается syswrite. И вот тут-то и возникает method „tid“ via package „threads“ at /usr/share/perl/5.18/XSLoader.pm .
Причём именно при таких действиях, этот syswrite вызывается в модуле логгера, и вызывается на каждый чих. А вот именно при вызове из $SIG{__DIE__} ...

Xellos ★★★★★
() автор топика
Ответ на: комментарий от Xellos

Вывести код не могу, могу порезать и показать «эквивалентный», но лучше опишу словами.

Это в 10 раз хуже. Потому что это событийка! Тут нет линейности, нет детерминированности.

Есть perl-скрипт...

Итак, из твоей писанины ясно следующее:

package My;

use JSON::XS ();

sub run {
    http_request
        POST => 'http://localhost/hello',
        headers => {
            'content-type' => 'application/json',
        },
        timeout => 15,
        body => &JSON::XS::encode_json({
            id => ++$RID,
            method => 'hello',
            params => [ ]
        }),
        sub {
          my ($data, $headers) = @_;

          if (200 == $headers->{Status}) {
            # ok
          } else {
            die $headers->{Reason};
          }
        },
    ;
}

package main;

use AnyEvent;

my $cv = AE::cv;

my $t = AE::timer 1, 1, sub {

  $SIG{__DIE__} = sub {
    printf "I will not do like this anymore\n";
  };

  &My::run();
};

$cv->recv;
Надеюсь, не надо пояснять почему так делать нельзя?

gh0stwizard ★★★★★
()
Ответ на: комментарий от gh0stwizard

Нет, не сработало. Сейчас $SIG{__DIE__} поставил в BEGIN-блок, это ничего не изменило. До этого он был просто в модуле. Сам модуль создаётся до запуска таймера.

Xellos ★★★★★
() автор топика
Ответ на: комментарий от Xellos

Ну вообще local локализует область значения переменной. Т.е. при указании local $SIG{__DIE__} = sub {} обработчик будет вызываться только в текущей области видимости. Если указано в пакете, то в области всего пакета. В подпрограмме - в области подпрограммы. И т.д.
А без local он действовал глобально, и видимо перекрывал чей-то другой обработчик $SIG{__DIE__}.

Olegymous ★★★
()
Ответ на: комментарий от Olegymous

То есть откуда брался object method „tid“ via package „threads“ так и неизвестно :(
А local внутри BEGIN как будет работать?

в области всего пакета

Меня всегда смущали немного перловые «области». Если я из пакета вызываю функцию другого пакета, и внутри неё происходит смерть - вызывается обработчик или нет?

Xellos ★★★★★
() автор топика
Ответ на: комментарий от Xellos

Ну судя по всему по причине перекрытия чье-го то другого обработчика die.
Кстати локализовать в области видимости пакета, как я писал что-то не получается. Тогда такой вариант

package B;

sub bad {
	die "I'm bad";
}

package A;

sub die_handler {
	warn "Died";
}

sub foo {
	local $SIG{__DIE__} = \&die_handler;
	
	print "I'm foo\n";
};

sub bar {
	local $SIG{__DIE__} = \&die_handler;
	
	B::bad();
}

1;

use strict;
use lib 'lib';
use A;

A::foo();
A::bar();

Если я из пакета вызываю функцию другого пакета, и внутри неё происходит смерть - вызывается обработчик или нет?

Как видим вызывается.

Olegymous ★★★
()
Ответ на: комментарий от Olegymous

Или вообще обрабатывать die в главной программе. Тогда будет так

package B;

sub bad {
	die "I'm bad";
}

package A;

sub foo {
	print "I'm foo\n";
};

sub bar {
	B::bad();
}

1;

use strict;
use lib 'lib';
use A;
# other code
....
{
	local $SIG{__DIE__} = sub {
		warn "died";
	};
	
	A::foo();
	A::bar();
}
#other code
...
Olegymous ★★★
()
Последнее исправление: Olegymous (всего исправлений: 2)

Кстати, а что вы делаете в обработчике die? Перехват исключений с помощью eval не подходит?
Ну и еще может понадобиться в обработчике проверить, что он поимал die вызванный за пределами eval блока. Что обычно имеет смысл. Вот пример из моего скрипта, обработчик использовался для нотификации по e-mail о помирании скрипта:

$SIG{__DIE__} = sub {
	unless ($^S) { # we are not inside eval
		# notify admin
		send_mail($MAIL_CFG->{__admin}, "fatal error at " . localtime(),
					"Script received \$SIG{__DIE__} with the following message:\n@_");
	}
};

Olegymous ★★★
()
Ответ на: комментарий от Olegymous

Мне не столько нужно их ловить, смерть это смерть, мне нужно поймать их вывод и красиво его записать куда надо.

unless ($^S) { # we are not inside eval

О, спасибо! Это мы прилепим обязательно. И возможно это само по себе решит проблему, даже без local.

Xellos ★★★★★
() автор топика
Ответ на: комментарий от Olegymous

А такой вопрос вдруг возник. Вот даже в приведённом примере - мы схватили die, и отослали письмо куда следует. А нам не нужно случайно сказать «а теперь помирай дальше»? Мы перехватом никакую цепочку событий не нарушили?

Что-то у меня вдруг нубские вопросы пошли :(

Xellos ★★★★★
() автор топика
Ответ на: комментарий от Xellos

Нет, после выполнения обработчика он сам продолжит помирать.

Olegymous ★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.