У меня есть Perl-программа с графическим интерфейсом GTK2 (через пакет Gtk2
). Эта программа также открывает сетевой сокет (фактически через LWP
) в другом потоке и непрерывно делает запрос на определенный URL, ожидая события.
Если событие происходит, то его данные должны быть обработаны и интерпретированы, а соответствующая функция обратного вызова используется для обновления GUI. Это где моя программа падает.
Основная программа:
# Attach to the "message received" event
Foo::hook('msgRx', \&updateMsg);
# ...
Gtk2->main();
sub updateMsg {
my ($msg) = @_;
print "New message: $msg\n";
# append to a GTK TextView -- code is also used elsewhere and works fine
appendMsg($msg);
}
А в модуле:
# ...
my %hooks = ();
my $ev_pid = undef;
sub hook($&) {
my ($name, $sub) = @_;
$hooks{$name} = $sub;
}
sub call_hook {
my ($name, @args) = @_;
print ">>> CALLING HOOK $name\n";
return $hooks{$name}->(@args) if (defined($hooks{$name}));
}
sub eventThread {
while (1) {
my $res = $browser->post("$baseurl/events", ['id' => $convid]);
my $content = $res->content;
last if ($content eq 'null');
my $events = from_json($content);
foreach (@$events) {
my $ev_type = shift @$_;
my @ev_args = @$_;
print "Event type: $ev_type\n";
print Data::Dumper->Dump([@ev_args]);
handleEvent($ev_type, @ev_args);
}
}
}
sub doConnect() {
# ...
$ev_pid = fork;
if (!defined $ev_pid) {
print "ERROR forking\n";
disconnect();
return;
}
if (!$ev_pid) {
eventThread;
exit;
}
}
Теперь вывод консоли на то, что я ожидаю:
>> Starting...
[["connected"]]
Event type: connected
>>> CALLING HOOK start
[["waiting"]]
Event type: waiting
>>> CALLING HOOK waiting
[["gotMessage", "77564"]]
Event type: gotMessage
$VAR1 = '77564';
>>> CALLING HOOK msgRx
New message: 77564
[["idle"]]
Event type: idle
>>> CALLING HOOK typing
[["gotMessage", "816523"]]
Event type: gotMessage
$VAR1 = '816523';
>>> CALLING HOOK msgRx
New message: 816523
>> User ending connection
null
>>> CALLING HOOK end
Однако текстовый интерфейс GUI не обновляется. Я могу только предположить, что это потому, что обратный вызов на самом деле происходит в другом потоке, который имеет дубликаты объектов.
Есть предложения?