Я хотел бы написать приложение 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 должна снова стать доступной.
Такой подход отлично работает в C/C++ под Win32, Linux с использованием родных библиотек GUI и/или 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);
});
});
В порядке ли мой код?
Я спрашиваю, потому что при его запуске графический интерфейс не отображает кнопку Thread и сообщает о следующей ошибке:
Gtk-CRITICAL **: gtk_box_pack: assertion `GTK_IS_WIDGET (child)' failed at vbox.pl line 48. (Where I use pack_start) GLib-GObject-WARNING **: invalid (NULL) pointer instance at vbox.pl line 67. GLib-GObject-CRITICAL **: g_signal_connect_closure: assertion `G_TYPE_CHECK_INSTANCE (instance)' failed at vbox.pl line 67. (the signal_connect doesn't work)
По-видимому, это не работает со сложными объектами.
Я пробовал другое решение, опрашивая запущенные потоки внутри функции обратного вызова, вызываемой в основном (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++. Я немного разочарован.
У кого-нибудь есть еще предложения? Является ли многопоточный API настолько нестабильным в Perl?
Последнее обновление. Этот код работает:
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) я должен опрашивать потоки (не очень ресурсоемкий для современных процессоров, но НЕ элегантный... следует полагаться только на примитивы синхронизации ОС)
2) я могу не присоединяйтесь к тредам, иначе апплет вылетит
3) Учитывая (2) огромные утечки памяти каждый раз, когда я нажимаю кнопку
Честно говоря, чем больше я это вижу, тем больше убеждаюсь, что для правильной разработки приложений вы не можете полагаться на Perl... но даже с точки зрения прототипа это отстой.
Надеюсь, я делаю что-то не так... в этом случае кто-нибудь может мне помочь?
Ваше здоровье,
$jobA
и$jobB
вне третьей темы? - person Sinan Ünür   schedule 17.08.2009