I have a Perl program that has a GTK2 GUI (via the Gtk2
package). This program also opens a network socket (actually via LWP
) in another thread, and continuously makes a request for a certain URL, waiting for an event to happen.
我有一个Perl程序,它有一个GTK2 GUI(通过Gtk2包)。该程序还在另一个线程中打开一个网络套接字(实际上是通过LWP),并不断发出某个URL的请求,等待事件发生。
If an event occurs, then its data must be processed and interpreted, and an appropriate callback function used to update the GUI. This is where my program falls down.
如果发生事件,则必须处理和解释其数据,并使用适当的回调函数来更新GUI。这是我的计划失败的地方。
Main program:
# 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);
}
And in the module:
在模块中:
# ...
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;
}
}
Now the console output from these is what I expect:
现在这些控制台输出是我所期望的:
>> 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
However, the GUI TextView does not update. I can only presume that this is because the callback is actually happening in another thread, which has duplicates of the objects.
但是,GUI TextView不会更新。我只能假设这是因为回调实际上发生在另一个线程中,该线程具有对象的副本。
Any suggestions?
2 个解决方案
#1
If you are forking, you need to implement some kind of IPC mechanism between your processes. In this case, a simple socket pair that connects the parent and child processes should suffice. See "Bidirectional Communication with Yourself" in perlipc on how to do this.
如果您要分叉,则需要在流程之间实现某种IPC机制。在这种情况下,连接父进程和子进程的简单套接字对应该足够了。请参阅perlipc中的“与自己双向通信”,了解如何执行此操作。
If the child process has new data available, just write it to the socket. In the main process, install a listener for the socket (I assume Gtk2 uses Glib under the hood, if so then Glib::IO::add_watch is what you need). If new data is available, the handler will be called and can update your GUI.
如果子进程有新数据可用,只需将其写入套接字即可。在主进程中,为套接字安装一个监听器(我假设Gtk2在引擎盖下使用Glib,如果是这样的话,那么Glib :: IO :: add_watch就是你需要的)。如果有新数据可用,则会调用处理程序并可以更新GUI。
#2
First of all, when you use fork
you are creating another process.
首先,当你使用fork时,你正在创建另一个进程。
Perl has, by default, the threads
module which can create real threads, if your perl was compiled with threads support.
默认情况下,Perl具有可以创建实际线程的线程模块,如果您的perl是使用线程支持编译的。
Unfortunately the current perl's thread implementation is far away from what you have on other languages, and I would advise not to use it.
不幸的是,当前的perl的线程实现与你在其他语言上的实现相差甚远,我建议不要使用它。
Some references for that are:
一些参考资料是:
perldoc threads
perldoc threads::shared
Good luck!
#1
If you are forking, you need to implement some kind of IPC mechanism between your processes. In this case, a simple socket pair that connects the parent and child processes should suffice. See "Bidirectional Communication with Yourself" in perlipc on how to do this.
如果您要分叉,则需要在流程之间实现某种IPC机制。在这种情况下,连接父进程和子进程的简单套接字对应该足够了。请参阅perlipc中的“与自己双向通信”,了解如何执行此操作。
If the child process has new data available, just write it to the socket. In the main process, install a listener for the socket (I assume Gtk2 uses Glib under the hood, if so then Glib::IO::add_watch is what you need). If new data is available, the handler will be called and can update your GUI.
如果子进程有新数据可用,只需将其写入套接字即可。在主进程中,为套接字安装一个监听器(我假设Gtk2在引擎盖下使用Glib,如果是这样的话,那么Glib :: IO :: add_watch就是你需要的)。如果有新数据可用,则会调用处理程序并可以更新GUI。
#2
First of all, when you use fork
you are creating another process.
首先,当你使用fork时,你正在创建另一个进程。
Perl has, by default, the threads
module which can create real threads, if your perl was compiled with threads support.
默认情况下,Perl具有可以创建实际线程的线程模块,如果您的perl是使用线程支持编译的。
Unfortunately the current perl's thread implementation is far away from what you have on other languages, and I would advise not to use it.
不幸的是,当前的perl的线程实现与你在其他语言上的实现相差甚远,我建议不要使用它。
Some references for that are:
一些参考资料是:
perldoc threads
perldoc threads::shared
Good luck!