次のようなPerlGTK+アプリケーションを作成したいと思います。
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が再び有効になります。
現在、この種のアプローチは、ネイティブGUIライブラリおよび/またはGTK +、KDEを使用するWin32、LinuxのC /C++で完全に有効です。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を実行すると、 [スレッド]ボタンが表示されず、次のエラーが報告されるため、質問しています。
Gtk-CRITICAL **:gtk_box_pack:アサーション `GTK_IS_WIDGET(child)'がvbox.plの48行目で失敗しました。(pack_startを使用する場合) GLib-GObject-警告**:vbox.plの67行目の無効な(NULL)ポインタインスタンス。 GLib-GObject-CRITICAL **:g_signal_connect_closure:アサーション `G_TYPE_CHECK_INSTANCE(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) 2番目のスレッドの結合
に
コメントする必要があります。
#$jobB->join();
そうしないと、アプレットがクラッシュします。
2)どうやら動作しているようですが、再度有効にしたボタンを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)スレッドをポーリングする必要があります(最新のCPUにはあまりリソースを消費しませんが、エレガントではありません... OS同期プリミティブのみに依存する必要があります)
2)スレッドに参加できません。そうしないとアプレットがクラッシュします
3)与えられた(2 )ボタンを押すたびに大量のメモリリークが発生します
正直なところ、これを見れば見るほど、適切なアプリ開発のためにPerlに頼ることはできないと確信しています...しかし、プロトタイプの観点からさえ、それはちょっとひどいです。
私は何か間違ったことをしているといいのですが...この場合、誰かが私を助けてくれますか?
乾杯、