私はかなり単純な Cアプリケーション をGTKを使用して構築していますが、GUIの更新をトリガーするブロッキングIOを実行する必要があります。これを行うには、 gtk_main()
の直前に新しいpthread
を開始します。
_/* global variables */
GMainContext *mainc;
/* local variables */
FILE *fifo;
pthread_t reader;
/* main() */
mainc = g_main_context_default();
pthread_create(&reader, NULL, watch_fifo, argv[argc-1]);
gtk_main();
_
pthread
がデータを読み取ると、次のようにGUIが更新されます。
_g_main_context_invoke(mainc, set_icon, param);
_
_set_icon
_は
_gboolean set_icon(gpointer data)
{
char *p = (char*)data;
gtk_status_icon_set_from_icon_name(icon, p);
return FALSE;
}
_
これはほとんどの場合機能しますが、時々、この奇妙なエラーメッセージが表示されます。
[xcb]キューの処理中にシーケンス番号が不明です [xcb]これはマルチスレッドクライアントであり、XInitThreadsが呼び出されていない可能性があります [xcb]中止、申し訳ありません。 mktrayicon:xcb_io.c:274:poll_for_event:アサーション `!xcb_xlib_threads_sequence_lost 'が失敗しました。
_g_main_context_invoke
_を使用することの全体的なポイントは、スレッドの問題を回避することだと思いましたか?グーグルを少しやってみると、_gdk_threads_init
_、_gdk_threads_enter
_とその友達に出くわしましたが、それらはすべて非推奨のようですか? GTKのドキュメントには、すべてのGUI更新はメインスレッドで実行する必要があると記載されていますが、これはIOのブロックとうまく組み合わされていないため、スレッド間に複雑な通信メカニズムを構築する必要はありません。
だから、私の質問は、これに正しく対処するにはどうすればよいですか?
編集:完全なコードを見ることができます ここ 編集2:@ptomatoの回答に基づく更新として、私はGThread
sに移動し、gdk_threads_add_idle()
を使用しています。 this commitですが、問題はまだ存在します。
XInitThreads()
を呼び出します。これは_gtk_init
_の前に実行する必要があります。これにより、メッセージが停止します。
このようなもの:
_ #include <X11/Xlib.h>
...
XInitThreads();
...
gtk_init(&argc, &argv);
_
g_thread_init()
/gdk_threads_init()
が使用されたときに、GLIB2.32より前にこれらのメッセージが表示されたのを覚えていません。
_g_thread_pool_new
_と_g_thread_pool_Push
_をチェックすることをお勧めします。スレッドから、_g_main_context_invoke
_を使用してメインループで実行するか、gdk_threads_enter()
/gdk_threads_leave()
の間でスレッドをラップします。
トレーを使わないのでなかなか確認できません。 GTK/GDKAPIを保護するためにロックを使用するgdk_threads_add_idleについては正しいと思います。これらのメッセージが表示される原因となる明らかなことは何もありません。 gtk_status_icon_new_from_icon_nameの関数の説明には、「現在のアイコンテーマが変更されると、アイコンが適切に更新されます。これは、Xディスプレイにアクセスするコードがコードだけではないことを意味し、問題が発生する可能性があります。
XInitThreads()に関するいくつかの関連情報もあります。
GDKはディスプレイにロックを使用しますが、GTK/GDKはXInitThreadsを呼び出さないことに注意してください。
補足:fork()の後にexeclに渡されるグローバル変数 "onclick"を保護しているのは、子が親のメモリロックを継承せず、GLibメインループがfork()と互換性がないことです。文字列をローカル変数にコピーできるかもしれません。
ベアpthreadがGTKで動作することが保証されているかどうかはわかりません。 GThreadラッパーを使用する必要があります。
問題は、g_main_context_invoke()
がアイドル関数としてset_icon()
を追加していることだと思います。 (それが舞台裏で行われているようですが、よくわかりません。)GLibのAPIを使用して追加されたアイドル関数は、メインスレッドで実行されているにもかかわらず、GDKロックを保持する必要があります。 gdk_threads_add_idle()
API(非推奨ではありません)を使用してset_icon()
を呼び出す場合、すべてがスレッド化で正しく機能するはずです。
(これは単なる推測ですが。)
回避策として、いくつかのIOを待っている間にUIをブロックしないようにしたい場合は、非同期IO from [〜 #〜] gio [〜#〜] 。これにより、スレッドを自分で管理する必要がなくなります。
編集:それについて考えると、ファイル記述子を非ブロッキングとしてマークし、それらをソースとしてglibメインループに追加するだけで、スレッドをいじることなくメインイベントループでそれらをポーリングします。
チャネルで利用可能なデータがある場合にコールバック関数を呼び出すgio_add_watch()を使用することで、スレッドの使用を回避できます。