Как я могу получить межпотоковое взаимодействие в программе Perl GTK? - PullRequest
1 голос
/ 12 июня 2009

У меня есть 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 не обновляется. Я могу только предположить, что это потому, что обратный вызов на самом деле происходит в другом потоке, который имеет дубликаты объектов.

Есть предложения?

Ответы [ 2 ]

1 голос
/ 12 июня 2009

Если вы разветвляетесь, вам нужно внедрить какой-то механизм IPC между вашими процессами. В этом случае достаточно простой пары сокетов, которая соединяет родительский и дочерний процессы. См. «Двунаправленное общение с самим собой» в perlipc о том, как это сделать.

Если у дочернего процесса есть новые доступные данные, просто запишите их в сокет. В основном процессе установите прослушиватель для сокета (я предполагаю, что Gtk2 использует Glib под капотом, если так, то Glib :: IO :: add_watch - это то, что вам нужно). Если доступны новые данные, будет вызван обработчик, который может обновить ваш графический интерфейс.

0 голосов
/ 12 июня 2009

Прежде всего, когда вы используете fork, вы создаете другой процесс.

В Perl по умолчанию установлен модуль threads, который может создавать реальные потоки, если ваш perl был скомпилирован с поддержкой потоков.

К сожалению, текущая реализация потока perl очень далека от того, что у вас есть на других языках, и я бы посоветовал не использовать его.

Вот некоторые ссылки:

perldoc threads
perldoc threads::shared

Удачи!

...