【问题标题】:How can I get cross-thread communication in a Perl GTK program?如何在 Perl GTK 程序中进行跨线程通信?
【发布时间】:2009-06-12 13:47:31
【问题描述】:

我有一个带有 GTK2 GUI 的 Perl 程序(通过 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;
    }
}

现在这些控制台输出是我所期望的:

>> 开始...
[[“连接的”]]
事件类型:已连接
>>> CALLING HOOK 开始
[[“等待”]]
事件类型:等待
>>> 呼叫挂钩等待
[["gotMessage", "77564"]]
事件类型:getMessage
$VAR1 = '77564';
>>> 呼叫挂钩 msgRx
新消息:77564
[[“闲”]]
事件类型:空闲
>>> CALLING HOOK 打字
[["gotMessage", "816523"]]
事件类型:getMessage
$VAR1 = '816523';
>>> 呼叫挂钩 msgRx
新消息:816523
>> 用户端连接
空值
>>> CALLING HOOK 结束

但是,GUI TextView 不会更新。我只能假设这是因为回调实际上是在另一个线程中发生的,该线程具有重复的对象。

有什么建议吗?

【问题讨论】:

    标签: perl multithreading gtk ipc


    【解决方案1】:

    如果你在分叉,你需要在你的进程之间实现某种 IPC 机制。在这种情况下,连接父进程和子进程的简单套接字对就足够了。请参阅 "Bidirectional Communication with Yourself" in perlipc 了解如何执行此操作。

    如果子进程有新数据可用,只需将其写入套接字即可。在主进程中,为套接字安装一个监听器(我假设 Gtk2 在后台使用 Glib,如果是这样,那么 Glib::IO::add_watch 就是你所需要的)。如果有新数据可用,将调用处理程序并更新您的 GUI。

    【讨论】:

    • 完美:GLib::IO::add_watch 正是我所需要的。然后我可以在 open $fh, '-|' 中使用隐式分叉并使用该文件句柄。谢谢!
    【解决方案2】:

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

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

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

    一些参考是:

    perldoc threads
    perldoc threads::shared
    

    祝你好运!

    【讨论】:

    • 我知道可能是这样。可悲的是,我不能依赖threads 可用。不过谢谢:-)
    • 正如趋势建议的那样,您可以使用 IPC 来解决您的进程通信问题。
    猜你喜欢
    • 2012-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-09
    相关资源
    最近更新 更多