代码之家  ›  专栏  ›  技术社区  ›  DMI

如何在Perl GTK程序中实现跨线程通信?

  •  1
  • DMI  · 技术社区  · 15 年前

    我有一个Perl程序,它有一个GTK2GUI(通过 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

    有什么建议吗?

    2 回复  |  直到 15 年前
        1
  •  1
  •   trendels    15 年前

    如果您正在分叉,您需要在流程之间实现某种IPC机制。在这种情况下,连接父进程和子进程的简单套接字对就足够了。看见 "Bidirectional Communication with Yourself" in perlipc 关于如何做到这一点。

    如果子进程有新数据可用,只需将其写入套接字即可。在主进程中,为套接字安装侦听器(我假设Gtk2在引擎盖下使用Glib,如果是这样的话) Glib::IO::add_watch 这是你需要的)。如果有新数据可用,将调用处理程序并更新GUI。

        2
  •  0
  •   Igor    15 年前

    首先,当你使用 fork 您正在创建另一个进程。

    默认情况下,Perl具有 threads 模块,它可以创建真正的线程,如果您的perl是使用线程支持编译的。

    不幸的是,当前perl的线程实现与其他语言的线程实现相差甚远,我建议不要使用它。

    这方面的一些参考资料如下:

    perldoc threads
    perldoc threads::shared
    

    祝你好运