2013-09-05 35 views
9

GTK kullanarak oldukça basit bir C application yapıyorum, ancak GUI güncellemelerini tetikleyecek bazı engelleme IO'ları gerçekleştirmeliyim. Bunu yapmak için, ben gibi gtk_main() önce yeni pthread hakkını başlatın:GTK ile sorun giderme sorunları

g_main_context_invoke(mainc, set_icon, param); 

Nerede set_icon

geçerli: pthread bazı verileri okuduğunda

/* 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(); 

, GUI şöyle günceller

gboolean set_icon(gpointer data) 
{ 
    char *p = (char*)data; 
    gtk_status_icon_set_from_icon_name(icon, p); 
    return FALSE; 
} 

Bu, çoğu zaman çalışır, ancak her seferinde bu ilginç hata iletisini alıyorum:

 
[xcb] Unknown sequence number while processing queue 
[xcb] Most likely this is a multi-threaded client and XInitThreads has not been called 
[xcb] Aborting, sorry about that. 
mktrayicon: xcb_io.c:274: poll_for_event: Assertion `!xcb_xlib_threads_sequence_lost' failed. 

g_main_context_invoke'u kullanmanın tüm noktası, iş parçacıklarıyla ilgili sorunları önlemek olduğunu düşündüm? Biraz Googling yaparak, gdk_threads_init, gdk_threads_enter ve arkadaşlarına rastladım, ancak bunların hepsi kullanımdan kaldırıldı mı? GTK belgelerinin, tüm GUI güncellemelerinin ana iş parçacığı üzerinde gerçekleştirilmesi gerektiğini söylediğini biliyorum, ancak bu, IO'yu bloke etmekle bütün bunları iyi bir şekilde birleştirmiyor ve iş parçacıkları arasında bazı karmaşık iletişim mekanizmalarını oluşturmamayı tercih ediyorum.

Ve benim sorum şu, bununla nasıl başa çıkmalıyım?

DÜZENLEME: Tam kod EDIT2 here görülebilir: @ ptomato en yanıta göre bir güncelleme, ben GThread s taşındı ve taahhüt this görülen, ancak sorun hala mevcut olduğu gibi gdk_threads_add_idle() kullanarak ettiğimiz gibi.

+0

Biraz kodunuz var mı, oldukça uzun bir süredir gtk + kullanıyorum ve _never_ bu konuda tökezledim .. – drahnr

+0

Tüm kod [GitHub] adresinde bulabilirsiniz (https://github.com/jonhoo/mktrayicon) gönderiye bağlı olarak. –

+0

Ah, teşekkür etti! – drahnr

cevap

8

Çağrı XInitThreads(). Bu, mesajları durduracak olan gtk_init'dan önce yapılmalıdır! Böyle

şey: Ben g_thread_init()/gdk_threads_init() kullanıldı GLib'in 2.32, önce bu mesajları gördüğümü hatırlamıyorum

#include <X11/Xlib.h> 
    ... 
    XInitThreads(); 
    ... 
    gtk_init(&argc, &argv); 

.

g_thread_pool_new ve g_thread_pool_push adreslerini incelemek isteyebilirsiniz. dizisinden , çok daha anlaşılır bir şekilde kontrol edemez bir tepsi kullanmayan sadece gdk_threads_enter()/gdk_threads_leave()

arasındaki iplik sarmak ana döngü veya içinde yürütmek için g_main_context_invoke kullanın.Ben GTK/GDK API korumak için kilitleri kullanarak gdk_threads_add_idle hakkında doğru olduğunu düşünüyorum. Bu mesajların görünmesine neden olacak hiçbir şey yoktur. Gtk_status_icon_new_from_icon_name için işlev açıklaması, "Geçerli simge teması değiştirilirse, simge düzgün şekilde güncellenecektir. Bana göre, kodunuz, X ekranına erişebilecek olan yalnızca kodu değil, potansiyel olabilir. sorun.

GDK ekran için kilitleri kullanır iken, GTK/GDK değil hiç çağrı XInitThreads yapmak

What is the downside of XInitThreads()?

not at XInitThreads() ile ilgili bazı ilgili bilgi de bulunmaktadır.Yan not : bir çatal (sonra Execl geçirilir "onclick" küresel değişkeni,) koruyor Ne, çocuk ebeveynin hafıza kilitlerini miras olmayacak ve GLib mainloop çatal ile uyumsuz() . Belki dizeyi yerel değişkene kopyalayabilirsiniz.

+0

'gdk_threads_enter' ve' gdk_threads_leave' kullanımdan kaldırıldı, bu yüzden bunları kullanmak gerçekten bir seçenek değil. Sadece bir ek iş parçacığım olduğunu düşündüğümde, bir iş parçacığı havuzu kullanmak biraz aşırı görünüyor, ama bahşiş için teşekkürler! "XInitThreads" adlı el kitabını manuel olarak belirten garip görünüyor. "GLib iş parçacığı sistemi programınızın başlangıcında otomatik olarak başlatılıyor", ama ben bunu daha sonra bugün vereceğim ve geri bildireceğim. –

+1

Ayrıca değil o gdk_threads_add_idle_full' 'belgeleri o "GDK ile function' düzenlenen kilidi 'çağırır" ve 'XInitThreads' dokümanlar "demek olduğunu söylediği zaman XInitThreads' 'aramak zorunda garip biraz tüm aramalar ise Xlib işlevlerine başka bir erişim mekanizması (örneğin, bir araç setindeki bir karşılıklı dışlama kilidi veya açık istemci programlama yoluyla) tarafından korunur, Xlib iş parçacığı başlatılması gerekli değildir "? –

+0

[Bu] (https://github.com/Jonhoo/mktrayicon/commit/77a869fd4612c0cdffdee2f19ae5db3dda77adb6) sorunu sabit, teşekkür ederim! Yine de ** hakkında daha fazla bilgi istiyorum. Neden ** bu ödül için oluyor. –

1

Çıplak pthreads'ın GTK ile çalışmasının garanti edilip edilmediğinden emin değilim. GThread sarmalayıcılarını kullanmalısınız.

Sorun, g_main_context_invoke()'un boş bir işlev olarak set_icon() eklediği sorun olabilir. (Görünüşe göre sahnelerin gerisinde olan budur, ama emin değilim.) GLIP'in API'sini kullanarak eklenen ana işlevler, ana iş parçacığı üzerinde yürütülmesine rağmen, GDK kilidini tutmalıdır. set_icon()'u çağırmak için gdk_threads_add_idle() API'sini (kullanımdan kaldırılmayan) kullanırsanız, her şey düzgün bir şekilde iş parçacığıyla çalışmalıdır.

(bu sadece bir tahmin olmasına rağmen.)

+0

Görüldüğü gibi GThreads ve 'gdk_threads_add_idle' olarak değiştirdim (https://github.com/Jonhoo/mktrayicon/commit/e62ede1cf0e863e0e9173d15f46a01bd6536fa11), ancak hala hatayı (veya bunun küçük varyasyonlarını) görüyorum. ara sıra ... –

+0

Evet, GTK ve PThreada uyumludur. – Lothar

0

Etrafa bir çalışma olarak, bazı IO'yu beklerken UI'yi engellemekten kaçınmak istiyorsanız, GIO'dan eşzamansız IO'yu kullanabilirsiniz. Bu, konuları kendiniz yönetmek zorunda kalmanızı engeller.

Düzenleme: Dosya tanımlayıcılarınızı engellemeyi engelleyici olarak işaretleyebilir ve bunları glib ana döngüsüne bir kaynak olarak ekleyebilir ve iş parçacıklarıyla uğraşmak zorunda kalmadan ana olay döngüsünde bunları sizin için yoklayabilir. .

+0

Yoklama, özellikle temiz bir çözüm gibi görünmüyor. Bunu engellemeyi tercih ederim, çünkü program hemen komutlara hemen tepki gösterecektir. GIO da ilginç görünüyor. Bunun için nasıl kullanabileceğimin bir örneğini verebilir misiniz? –

+0

Yoklama engelleme okumasından daha yavaş olmamalı, GTK'nın fare ve klavye olaylarına tepki vermek için kullandığı durum budur. Bunu yapmak için g_io_channel_new_file ile bir 'GIOChannel' oluşturun ve 'g_io_add_watch' ile ana döngüye ekleyin. GIO için 'g_file_new_for_commandline_arg' veya' g_file_new_for_path' ile bir 'GFile' oluşturun, ardından g_file_read_finish' olarak adlandırılan ve g_input_stream_read_async' ile 'g_input_stream_read_async' olarak adlandırılan ve g_input_stream_read_finish' olarak adlandırılan bir geri çağırma ile g_file_read_async' işlevini çağırın ve sonra okuduğunuz verileri işledikten sonra aramaları yapın. Tekrar g_input_stream_read_async'. –

0

Kanalda mevcut veriler olduğunda geri arama işlevini çağırmak olacaktır gio_add_watch() kullanarak konuları kullanarak önlemek olabilir.

+0

FIFO dosyaları ile tamamen önemsiz değil, çünkü onları kullandığım için, yazarlar gelip gittikçe EOF'un her seferinde yeniden açılmaları gerekecek (hangi bloklar). g_io_add_watch' bunu desteklemiyor mu? Yanlışsam düzelt. –

İlgili konular