Threading Probleme mit GTK
Baue ich eine ziemlich einfache C-Anwendung mit GTK, aber haben Sie einige blocking-IO, die Aktualisierungen an der Benutzeroberfläche. Um dies zu tun, starte ich einen neuen pthread
Recht vor gtk_main()
als solche:
/* 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();
Wenn die pthread
liest einige Daten, aktualisiert die GUI etwa so:
g_main_context_invoke(mainc, set_icon, param);
Wo set_icon
ist
gboolean set_icon(gpointer data)
{
char *p = (char*)data;
gtk_status_icon_set_from_icon_name(icon, p);
return FALSE;
}
Das ganze funktioniert die meiste Zeit, aber hin und wieder bekomme ich diese merkwürdige Fehlermeldung:
[xcb] Unbekannt-Sequenznummer, die während der Verarbeitung der Warteschlange [xcb] die Meisten wahrscheinlich, dass dies ist ein multi-threaded-client-und XInitThreads wurde nicht genannt [xcb] Abbrechen, tut mir Leid, dass. mktrayicon: xcb_io.c:274: poll_for_event: Assertion `!xcb_xlib_threads_sequence_lost' ist fehlgeschlagen.
Ich dachte, der ganze Punkt, der mit g_main_context_invoke
war Probleme zu vermeiden, die mit threads? Ein wenig Googeln stieß ich auf gdk_threads_init
, gdk_threads_enter
und Freunde, aber Sie alle scheinen veraltet? Ich kenne die GTK-Dokumentation besagt, dass alle GUI-updaes durchgeführt werden sollte, der Haupt-thread, aber das nicht kombinieren alle, die gut mit blocking-IO, und ich würde es vorziehen, nicht zu haben, zu konstruieren, die eine komplexe Kommunikation zwischen den threads.
Und so, meine Frage ist, wie ich richtig damit umgehen?
EDIT: Der vollständige code gesehen werden kann hier
EDIT2: ein update basierend auf dem @ptomato Antwort, ich habe verschoben, um GThread
s und mit gdk_threads_add_idle()
wie in diese Begehen, aber das problem ist immer noch vorhanden.
Der gesamte code ist verfügbar auf GitHub als mit der post.
Ah, übersehen, danke!
Beachten Sie, dass Sie verwenden werden dieser - link, um zu sehen, mit dem original-code, und dieser - link, um zu sehen, den code nach der Umsetzung der Vorschläge von @ptomato. Dieser - link verweist Sie auf die Feste version der Datei.
InformationsquelleAutor Jon Gjengset | 2013-09-05
Du musst angemeldet sein, um einen Kommentar abzugeben.
Call
XInitThreads()
. Dies sollte geschehen, bevorgtk_init
, das wird verhindern, dass die Nachrichten!Etwas wie dieses:
Ich erinnere mich nicht sehen, diese Nachrichten vor der GLIB 2.32, wenn
g_thread_init()
/gdk_threads_init()
verwendet wurden.Möchten Sie vielleicht zu prüfen, aus
g_thread_pool_new
undg_thread_pool_push
.Von Faden zu verwenden
g_main_context_invoke
zur Ausführung in der main-loop odernur wickeln Sie Faden zwischen
gdk_threads_enter()
/gdk_threads_leave()
Ich nicht mit einem Fach, so kann ich nicht einfach überprüfen. Ich denke, Sie sind
richtig über gdk_threads_add_idle mit einem Schloss zu schützen, GTK/GDK-API.
Es ist nichts für mich offensichtlich, dass würde dazu führen, dass diese Nachrichten an
erscheinen. Die Funktionsbeschreibung für die gtk_status_icon_new_from_icon_name
besagt, dass "Wenn die aktuelle icon-theme geändert wird, ist das Symbol
entsprechend aktualisiert. Was für mich impliziert dein code ist nicht der einzige
code, der auf der X-Anzeige, die möglicherweise die
problem.
Gibt es auch einige Verwandte Informationen über XInitThreads() bei
Was ist der Nachteil von XInitThreads()?
Beachten Sie, dass während der GDK verwendet sperren für die Anzeige, GTK/GDK nicht immer
rufen Sie XInitThreads.
On a side note: Was ist der Schutz der globalen variable "onclick", die
übergeben wird execl nach einem fork(), Das Kind wird nicht Erben die Eltern
memory-locks, und GLib-mainloop ist unvereinbar mit fork().
Vielleicht könnte Sie kopieren Sie die Zeichenfolge, um lokale Variablen.
gdk_threads_enter
undgdk_threads_leave
wurden abgelehnt, so ist das nicht wirklich eine option. Bedenkt, dass ich nur einen weiteren thread mit einem thread-pool scheint ein bisschen übertrieben, aber danke für den Tipp! Scheint seltsam zu nennenXInitThreads
manuell in das Handbuch sagt "Die GLib-threading-system, das automatisch initialisiert wird beim starten des Programms", aber ich werde es später heute und Bericht zurück.Auch ist es nicht ein bisschen seltsam zu nennen
XInitThreads
wenn die Dokumentation fürgdk_threads_add_idle_full
sagt, dass es "ruftfunction
mit der GDK Sperre", und dieXInitThreads
docs sagen ", Wenn Sie alle Anrufe, um Xlib-Funktionen sind geschützt durch einige andere access-Mechanismus (zum Beispiel eine gegenseitige Ausschluss Sperre in einem toolkit oder durch explizite client-Programmierung), Xlib thread-Initialisierung ist nicht erforderlich"?Dieser das problem wurde behoben, danke! Würde gern noch einige weitere Informationen auf warum dies geschieht für die bounty.
Nach dem Lesen den link in Ihrer Antwort auf
XInitThreads
bin ich mir nicht gefallen haben, es zu nennen, obwohl es funktioniert. Es scheint, als ob mitgdk_threads_add_idle
, die bereits erwirbt er das GTK-lock, sollte ausreichend sein... In Bezug auf Ihre Anmerkung, das sollte nicht das problem sein, da der Speicherplatz ist kopiert vonfork
und dann "ausgelöscht" vonexecl
. Die Elternonclick
var wird freigegeben, wenn es geändert wurde, weiter unten. Wenn Sie daran denken, X-sperren, die neufork
ed Prozess wird ganz unabhängig sein, und sollte nicht haben, um über sorgen GDK/GTK ab.Ich denke, dass dies möglicherweise ein bug in GTK oder GDK. Wenn Sie können, reduzieren Sie es auf ein minimal-Beispiel (zugegeben, schwer zu tun mit threading bugs) es trägt definitiv die Berichterstattung an die bugzilla.gnome.org.
InformationsquelleAutor Wiley
Ich bin mir nicht sicher, ob bare-pthreads sind garantiert zu arbeiten mit GTK. Sollten Sie die GThread-Wrapper.
Ich denke, was das problem sein kann ist, dass
g_main_context_invoke()
ist das hinzufügenset_icon()
als eine idle-Funktion. (Es scheint, dass das ist, was hinter den kulissen abläuft, aber ich bin mir nicht sicher.) Leerlauf-Funktionen Hinzugefügt, mit GLib API, obwohl Sie auf dem Hauptthread ausgeführt wird, zu halten brauchen die GDK sperren. Wenn Sie diegdk_threads_add_idle()
API (das ist nicht veraltet) zum aufrufenset_icon()
, dann sollte alles richtig funktionieren mit threading.(Dies ist zwar nur eine wilde Vermutung.)
gdk_threads_add_idle
gesehen in diesem commit, aber ich bin immer noch sehen, Fehler (oder kleinere Varianten davon) gelegentlich...Ja, GTK und PThreada kompatibel sind.
InformationsquelleAutor ptomato
Als eine Arbeit um, wenn Sie nur wollen, um zu vermeiden, Blockierung der Benutzeroberfläche während der Wartezeit für einige IO-könnten Sie die asynchrone IO von GIO. Das würde vermeiden, müssen Sie unter verwalten von threads selbst.
Edit: daran zu Denken, Sie könnten einfach markieren Sie Ihre Datei-Deskriptoren als nicht-blockierend, und fügen Sie Sie als Quelle, um die glib main loop und es wird die Umfrage für Sie in die Haupt-event-Schleife, die zimmerreserviereung, ohne das Sie Durcheinander über mit threads.
Polling sollte nicht langsamer als eine blockierende Lesen, es ist das, was GTK nutzt, um zu reagieren auf Maus-und Tastatur-Ereignisse. Um dies zu tun erstellen Sie eine
GIOChannel
mitg_io_channel_new_file
und fügen Sie es in die main loop mitg_io_add_watch
. Für GIO erstellen Sie eineGFile
mitg_file_new_for_commandline_arg
oderg_file_new_for_path
dann rufen Sieg_file_read_async
mit einem Rückruf, Anrufeg_file_read_finish
gefolgt vong_input_stream_read_async
mit einem Rückruf, Anrufeg_input_stream_read_finish
und verarbeitet dann die Daten Lesen und dann anrufeng_input_stream_read_async
wieder.InformationsquelleAutor Phillip Wood
Könnten Sie vermeiden, die Verwendung von threads durch Verwendung gio_add_watch() aufrufen, wird Ihre callback-Funktion, wenn es Daten auf dem Kanal.
g_io_add_watch
scheint nicht, dies zu unterstützen? Korrigieren Sie mich, wenn ich falsch bin.InformationsquelleAutor barry day