Threading problèmes avec GTK
Je suis en train de construire une assez simple C application utilisant GTK, mais ont à effectuer un certain blocage IO qui va déclencher les mises à jour de l'interface graphique. Pour ce faire, je commence une nouvelle pthread
juste avant gtk_main()
en tant que tel:
/* 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();
Lorsque le pthread
lit des données, des mises à jour de l'interface graphique comme suit:
g_main_context_invoke(mainc, set_icon, param);
Où set_icon
est
gboolean set_icon(gpointer data)
{
char *p = (char*)data;
gtk_status_icon_set_from_icon_name(icon, p);
return FALSE;
}
Tout cela fonctionne la plupart du temps, mais chaque maintenant et encore je obtenir de ce curieux message d'erreur:
[xcb] Inconnu numéro de séquence lors du traitement de la file d'attente [xcb] le Plus probable c'est un multi-thread client et XInitThreads n'a pas été appelé [xcb] l'Abandon, désolé. mktrayicon: xcb_io.c:274: poll_for_event: Assertion `!xcb_xlib_threads_sequence_lost' a échoué.
Je pensais que tout le point de l'utilisation de g_main_context_invoke
était pour éviter les problèmes avec les threads? En faisant un peu de recherche sur Google, je suis tombé sur gdk_threads_init
gdk_threads_enter
et des amis, mais ils semblent tous être obsolète? Je sais que le GTK documentation dit que tous les GUI updaes doit être effectuée sur le thread principal, mais cela ne les combine pas très bien avec le blocage des IO, et je préfère ne pas avoir à construire des complexes mécanisme de communication entre les threads.
Et donc, ma question est, comment dois-je traiter correctement avec cette?
EDIT: Le code complet peut être vu ici
EDIT2: Comme une mise à jour basé sur @ptomato réponse, j'ai déménagé à GThread
s et à l'aide de gdk_threads_add_idle()
comme on le voit dans cette s'engager, mais le problème est toujours présent.
source d'informationauteur Jon Gjengset
Vous devez vous connecter pour publier un commentaire.
Appel
XInitThreads()
. Cela devrait être fait avantgtk_init
qui arrête les messages!Quelque chose comme ceci:
Je ne me souviens pas avoir vu ces messages avant de GLIB 2.32, lorsque
g_thread_init()
/gdk_threads_init()
ont été utilisés.Vous pourriez vouloir vérifier
g_thread_pool_new
etg_thread_pool_push
.De fil, utiliser
g_main_context_invoke
à exécuter dans la boucle principale oujuste envelopper fil entre
gdk_threads_enter()
/gdk_threads_leave()
Je n'utilisez pas un bac donc je ne peux pas facilement vérifier cela. Je pense que vous êtes
correct sur gdk_threads_add_idle à l'aide de verrous pour protéger GTK/GDK API.
Il n'y a rien d'évident pour moi que serait la cause de ces messages
apparaissent. La description de la fonction pour gtk_status_icon_new_from_icon_name
"Si l'icône actuelle thème est modifié, l'icône sera
mis à jour en conséquence. Qui, pour moi, implique votre code n'est pas le seul
code d'accès de l'affichage X, ce qui pourrait être la
problème.
Il y a aussi quelques infos concernant XInitThreads() à
Quel est l'inconvénient de XInitThreads()?
Note que bien que GDK utilise des serrures pour de l'affichage, GTK/GDK ne jamais
appel XInitThreads.
Sur une note de côté: Quelle est la protection de la variable globale "onclick", qui
est passé à execl après un fork(), L'enfant ne pourra pas hériter d'un parent est
la mémoire des serrures, et GLib mainloop est incompatible avec fork().
Peut-être que vous pouvez copier la chaîne de caractères à une variable locale.
Je ne suis pas sûr si nu pthreads sont garantis de travailler avec GTK. Vous devez utiliser le GThread wrappers.
Je pense que le problème est peut-être que
g_main_context_invoke()
est l'ajout deset_icon()
comme une fonction inactive. (Il semble que c'est ce qui se passe derrière les scènes, mais je n'en suis pas sûr.) Inactif fonctions ajoutées à l'aide de GLib de l'API, en dépit d'être exécuté sur le thread principal, la nécessité de maintenir la GDK de verrouillage. Si vous utilisez legdk_threads_add_idle()
API (qui n'est pas obsolète) pour invoquerset_icon()
alors tout devrait fonctionner correctement avec le filetage.(Même si c'est juste un sauvage imagine.)
Pour contourner ce problème, si vous voulez juste pour éviter le blocage de l'INTERFACE utilisateur lors de l'attente pour certains IO vous pouvez utiliser le asynchrones IO GIO. Pour éviter d'avoir à gérer des threads de vous-même.
Edit: Penser à elle, vous pouvez simplement marquer votre descripteurs de fichiers non-bloquant et de les ajouter en tant que source de la glib boucle principale et il s'interroger pour vous dans la boucle principale sans avoir à se soucier avec les threads.
Vous pourriez éviter d'utiliser des threads en utilisant gio_add_watch() qui appelle votre fonction de rappel lorsque des données sont disponibles sur le canal.