2009-06-12 6 views
1

Ich habe ein Perl-Programm, das eine GTK2 GUI hat (über das Gtk2 Paket). Dieses Programm öffnet auch einen Netzwerk-Socket (eigentlich über LWP) in einem anderen Thread, und fordert ständig eine bestimmte URL an, auf ein Ereignis zu warten.Wie kann ich Cross-Thread-Kommunikation in einem Perl GTK-Programm bekommen?

Wenn ein Ereignis auftritt, müssen seine Daten verarbeitet und interpretiert werden und eine entsprechende Callback-Funktion zum Aktualisieren der GUI verwendet werden. Hier fällt mein Programm ab.

Hauptprogramm:

# 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); 
} 

Und in dem Modul ein:

# ... 
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; 
    } 
} 

Nun ist die Konsolenausgabe von diesen ist, was ich erwarten:

>> 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

jedoch die GUI Textview tut nicht aktualisieren. Ich kann nur vermuten, dass dies daran liegt, dass der Rückruf tatsächlich in einem anderen Thread stattfindet, der Duplikate der Objekte enthält.

Irgendwelche Vorschläge?

Antwort

1

Wenn Sie verzweigen, müssen Sie eine Art IPC-Mechanismus zwischen Ihren Prozessen implementieren. In diesem Fall sollte ein einfaches Socket-Paar ausreichen, das die Eltern- und Kindprozesse verbindet. Siehe dazu "Bidirectional Communication with Yourself" in perlipc.

Wenn der untergeordnete Prozess neue Daten verfügbar hat, schreiben Sie es einfach in den Socket. Installieren Sie im Hauptprozess einen Listener für den Socket (ich nehme an, Gtk2 verwendet Glib unter der Haube, wenn ja, dann ist Glib::IO::add_watch was Sie brauchen). Wenn neue Daten verfügbar sind, wird der Handler aufgerufen und kann Ihre GUI aktualisieren.

+0

Perfekt: GLib :: IO :: add_watch war genau das, was ich brauchte. Ich kann dann mit der impliziten Verzweigung in open $ fh auskommen, '- |' und benutze das Dateihandle. Vielen Dank! – DMI

0

Zunächst einmal, wenn Sie fork verwenden, erstellen Sie einen anderen Prozess.

Perl hat standardmäßig das Modul threads, das echte Threads erstellen kann, wenn Ihr Perl mit Threads-Unterstützung kompiliert wurde.

Leider ist die aktuelle Perl-Thread-Implementierung weit entfernt von dem, was Sie in anderen Sprachen haben, und ich würde empfehlen, es nicht zu verwenden.

Einige Referenzen dafür sind:

perldoc threads 
perldoc threads::shared 

Viel Glück!

+0

Ich wusste, dass das wahrscheinlich der Fall war. Leider kann ich mich nicht darauf verlassen, dass "Threads" verfügbar sind. Danke, aber :-) – DMI

+0

Als Trendel vorgeschlagen, könnten Sie IPC verwenden, um Ihre Prozesse Kommunikationsproblem zu lösen. – Igor