我想编写一个 Perl GTK+ 应用程序,它将:
0.1) 按下按钮 A
0.2) 禁用 A
0.3) 启动线程 1 和 2
0.4) 启动线程 3
线程 3 执行以下操作:
3.1) 加入线程 1
3.2) 加入线程 2
3.3) 启用 A
线程 3 完成后,应再次启用按钮 A。
现在,这种方法在 Win32 下的 C/C++、使用原生 GUI 库的 Linux 和/或 GTK+、KDE 下完全有效。GTK+ 和 Perl 的问题是您不能在线程内共享按钮变量(例如,第 3.3 点不能由线程 3 执行)。
问题是threads::shared仅适用于基本类型,而不适用于Gtk2::Button
.
我再次尝试bless
该Gtk2::Button
对象(如文档中所示),但出现错误:
my $thread_button = shared_clone(Gtk2::Button->new('_Threads'));
bless $thread_button => 'Gtk2::Button';
$hbox->pack_start($thread_button, FALSE, FALSE, 0);
my ($jobA, $jobB);
$thread_button->signal_connect( clicked => sub {
$thread_button->set_sensitive(0);
if (defined($jobA)) {
$jobA->join();
}
if (defined($jobB)) {
$jobB->join();
}
# spawn jobs
$jobA = threads->create(\&async_func, 10);
$jobB = threads->create(\&async_func, 10);
threads->create(sub {
$jobA->join();
$jobB->join();
bless $thread_button => 'Gtk2::Button';
$thread_button->set_sensitive(1);
});
});
我的代码可以吗?
我问是因为当它运行 GUI 时不会显示Thread按钮并报告以下错误:
Gtk-CRITICAL **: gtk_box_pack: 断言 `GTK_IS_WIDGET (child)' 在 vbox.pl 第 48 行失败。(我使用 pack_start 的地方) GLib-GObject-WARNING **:vbox.pl 第 67 行的无效(NULL)指针实例。 GLib-GObject-CRITICAL **:g_signal_connect_closure:断言“G_TYPE_CHECK_INSTANCE(实例)”在 vbox.pl 第 67 行失败。(signal_connect 不起作用)
显然这不适用于复杂的对象。
我尝试了另一种修复方法,轮询在主(GTK)线程中调用的回调函数内正在运行的线程:
my $thread_button = Gtk2::Button->new('_Threads');
$hbox->pack_start($thread_button, FALSE, FALSE, 0);
my ($jobA, $jobB);
$thread_button->signal_connect( clicked => sub {
$thread_button->set_sensitive(0);
# spawn jobs
$jobA = threads->create(\&async_func, 10);
$jobB = threads->create(\&async_func, 10);
Glib::Timeout->add(3000, sub {
print "TIMER\n";
if (defined($jobA)) {
if (! $jobA->is_running()) {
print "jobA is not running!\n";
$jobA->join();
undef $jobA;
}
}
if (defined($jobB)) {
if (! $jobB->is_running()) {
print "jobB is not running!\n";
#$jobB->join();
undef $jobB;
}
}
if (!defined($jobA) && !defined($jobB)) {
print "Both jobs have terminated!\n";
$thread_button->set_sensitive(1);
return 0;
}
return 1;
});
});
请注意以下几点:
1)我必须在第二个线程上评论加入
#$jobB->join();
否则小程序会崩溃。
2)显然它有效,但是当我第二次单击重新启用按钮时,线程创建使应用程序崩溃
这很不稳定。我认为 Perl 更基于 C,但这种巨大的不稳定性在 C/C++ 中完全不存在。我有点失望。
有人有更多建议吗?Perl 中的多线程 API 如此不稳定吗?
最近更新。此代码有效:
my $thread_button = Gtk2::Button->new('_Threads');
$hbox->pack_start($thread_button, FALSE, FALSE, 0);
my ($jobA, $jobB);
$thread_button->signal_connect( clicked => sub {
$thread_button->set_sensitive(0);
# spawn jobs
$jobA = threads->create(\&async_func, 10);
$jobB = threads->create(\&async_func, 10);
Glib::Timeout->add(100, sub {
if (!$jobA->is_running() && !$jobB->is_running()) {
print "Both jobs have terminated!\n";
$thread_button->set_sensitive(1);
return 0;
}
return 1;
});
});
但是:
1)我必须轮询线程(在现代 CPU 上资源不是很密集,但不是很优雅......应该只依赖操作系统同步原语)
2)我不能加入线程,否则小程序崩溃
3)给定(2 ) 每次按下按钮时都会出现巨大的内存泄漏
老实说,我看到的越多,我就越相信对于适当的应用程序开发,你不能依赖 Perl……但即使从原型的角度来看,它也有点糟糕。
我希望我做错了什么......在这种情况下,有人可以帮助我吗?
干杯,