GTK+ and threads question - "main" GTK+ lock.
Hello list ! I'm in the process of coding a multithreaded GTK+ application. The application opens a window which contenst is being updated by a worker thread, however it is possible that the window does not exist anymore (it received a "delete-event" signal) while the worker thread still tries to update it. To the window's "delete-event" signal a callback function is connected that sets some variable to NULL. Actually that variable is the window variable itself ('scan_status_window'). The code that does the update checks the value of that variable in the following manner: - gdk_threads_enter(); if ( scan_status_window == NULL ) { gdk_threads_leave(); return; } . . . /* Window update code runs here. */ . . . gdk_flush(); gdk_threads_leave(); return; - My question is whether assuming that 'scan_status_window' is being set to 'NULL' in a callback function that is holding the "main" GTK+ lock ('gdk_threads_enter()' called right before 'gtk_main()') it is guaranteed that when the window does not exist anymore 'scan_status_window' is set to 'NULL' ? Another words, whether update worker thread is unable to acquire the lock until callback function returns and vice versa, window destruction won't proceed until update worker thread releases the lock ? More precisely, whether "delete-event" signal reception, delivery and callback function execution operations are all executed within the "main" GTK+ lock (not just the callback function itself) ? Best regards Przemyslaw Tokarski Lodz, Poland PS. I'll summarize. ___ gtk-app-devel-list mailing list gtk-app-devel-list@gnome.org http://mail.gnome.org/mailman/listinfo/gtk-app-devel-list
Re: GTK and threads
Michael, thanks for your example. It works fine. I had done almost the same thing (see code below), but my mistake was in trying to call the function below from event-response functions within main() as well as from threads. In the case of main(), which is completely enclosed within gdk_threads_enter() and gdk_threads_leave(), the nested call to gdk_threads_enter() results in a total lockup of the application. Some of my other (defective) variations caused a total lockup of the gnome desktop. I am now trying to figure out my next approach: 1. Implement some kind of thread-specific global memory where I can save the GDK lock status of the thread and avoid the nested calls to gdk_threads_enter(). This seems impossible without modifying all functions to pass a thread-number argument or a pointer to the thread-specific memory. 2. Versions of my functions with and without the gdk_threads_enter() and _leave() calls (locking version calls non-locking version). Now I still have to figure out if being called from main() or a thread, or from another function that locks. 3. Do all GDK/GTK stuff within main() response functions, and deal with the application complexity of passing data back and forth between these functions and the thread functions. I am inclining to this because it is safe and sure. QUESTION I was hoping to find a way to send a text message to a window and have a corresponding response function, as for a menu selection or the "destroy" signal. I cannot find such a function, but surely this exists. regards Mike = // print to a text view window ala printf() void wprintf(GtkTextView *textWin, char *mess, ... ) { GtkTextBuffer *textBuff; GtkTextItertextIter; GtkTextMark*textMark; va_list arglist; char message[200]; va_start(arglist,mess); vsprintf(message,mess,arglist); va_end(arglist); gdk_threads_enter(); textBuff = gtk_text_view_get_buffer(textWin); gtk_text_buffer_get_end_iter(textBuff,&textIter); gtk_text_buffer_insert(textBuff,&textIter,message,-1); gtk_text_buffer_get_end_iter(textBuff,&textIter); textMark = gtk_text_buffer_create_mark(textBuff,0,&textIter,0); gtk_text_view_scroll_to_mark(textWin,textMark,0,0,1,1); gdk_flush();// needed ?? gdk_threads_leave(); } Michael Torrie wrote: kornelix wrote: Thanks. I eagerly anticipate your example. I have attached a sample file that uses threads in the way you described in your last post. The gui consists of a single text display and a button. When you click the button, a new thread is started that periodically (every second) sends a message to the text window. When you close the window, the program will send a signal to each thread to terminal (well not a real signal, just sets a flag). Once all the threads have terminated, the program ends. I have not implemented a proper signalling system to send signals to the threads nor have I used the pthread_join to properly rejoin threads that have quit. Mainly because pthread_join blocks and that causes problems. You'll notice the on_destroy callback has a loop that iterates the gtk event loop while we're waiting for the threads to stop. This is because we're in a callback, already holding the gdk_thread_lock, so any waiting in here will prevent threads from aquiring their lock and thus finishing their loops. So we iterate it. The callbacks (including the pthread_create calls) already occur in the context of the main gdk lock, so no explicit locking is needed there. See what you think. I made a small code example like the one you described. It hung up. Then I figured out why: I am calling a function that has the gdk_threads_enter() and _leave() wrappers from main() as well as from a created thread. In the case of main(), the call to gdk_threads_enter() was a second call for that thread, and this is apparently fatal. I have to figure out how to detect and avoid this, or make multiple versions of the functions with and without the wrappers. If I call the function from the thread only, it works. I really am not following what you are describing (please provide code) but it feels like you're definitely doing something wrong. It needn't be this complicated from my experience. One way of looking at the issue is that the FAQ example includes all main() code within the thread wrapper functions, meaning that any called functions better not have the wrappers. Would it be legitimate to treat main() like any other thread, and put the wrappers only around gtk/gdk calls? If I could do this, then functions would be usable from both main() and created threads. Hmm. Sounds complicated. My gut feeling is that most of your difficulties are in not knowing when you are in the gdk lock already and when you need to initiate a lock. Please tell me if my example code addresses any of the problems you have been having. (and for
Re: GTK and threads
Boncek, John wrote: How did you get an attachment to work with the list? I have never known that to work and often wished it would. I simply attached it normally and sent it off! Perhaps you have some attachment filtering on your mail server that you send through? I don't know. Michael ___ gtk-app-devel-list mailing list gtk-app-devel-list@gnome.org http://mail.gnome.org/mailman/listinfo/gtk-app-devel-list
Re: GTK and threads
Alan M. Evans wrote: I generally like to make code examples compile without warning. Did you even try to compile this? Of course. It definitely compiles. and runs without crashing. :) I'll ignore your snippy tone and say that, yes eliminating warning is a good thing. However for this example, I know exactly where the two warnings are and that they are harmless in this case. In fact one of them even comes from a snippet I borrowed from the gtk api docs. If you are getting more warnings or errors, rather than say "did you even bother to compile this?" just tell us the specifics and of course how to correct them. In the meantime, heaven help you if you build downloaded projects on linux on a regular basis. Some makefiles even redirect the warnings to /dev/null since there are so many (obviously not a great thing). Michael #include #include #include #include #include #include /* sleep() - on Unix, anyway */ gint thread_count=0; gint dead_threads; GSList *threads; struct thread_info_data { GtkTextBuffer *buffer; gint id; pthread_t tid; gint terminate; }; void thread (void *data) { void * thread(void *data) { struct thread_info_data *info; GtkTextIter iter; GString *message; info=(struct thread_info_data *)data; message=g_string_new(""); while(info->terminate == 0 ) { sleep(1); g_string_printf(message,"Thread %d here.\n",info->id); g_print("%s",message->str); gdk_threads_enter(); gtk_text_buffer_get_end_iter(info->buffer,&iter); gtk_text_buffer_insert(info->buffer,&iter,message->str,-1); gdk_threads_leave(); } g_print("Thread %d stopping.\n",info->id); gdk_threads_enter(); //borrowing a lock from gtk to lock our variable dead_threads++; gdk_threads_leave(); //we could and should use a counting semaphore g_string_free(message,NULL); g_string_free(message,FALSE); /* Hope NULL means FALSE here */ return 0; } void stop_thread(gpointer data, gpointer user_data) { struct thread_info_data *thread; thread=data; thread->terminate=1; g_print("Asked thread %d to stop.\n",thread->id); //here we ought to make sure the thread really has died // pthread_join(thread->tid,NULL); } void on_destroy(GtkWidget *widget, gpointer data) { g_slist_foreach(threads,stop_thread,NULL); while(dead_threads < thread_count) { while(gtk_events_pending()) { gtk_main_iteration(); } sleep(0); } gtk_main_quit(); } void on_button_clicked(GtkWidget *widget, gpointer data) { GtkTextBuffer *buffer; GtkTextIter iter; struct thread_info_data *thread_info; buffer=GTK_TEXT_BUFFER(data); thread_info=g_malloc(sizeof(struct thread_info_data)); thread_info->buffer=buffer; thread_info->id=thread_count++; thread_info->terminate=0; threads=g_slist_append(threads,thread_info); pthread_create(&(thread_info->tid),NULL,thread,thread_info); gtk_text_buffer_get_end_iter(buffer,&iter); gtk_text_buffer_insert(buffer,&iter,"Button clicked!\n",-1); g_print("Button clicked.\n"); } int main(int argc, char *argv[]) { GtkWidget *window; GtkWidget *button; GtkWidget *vbox; GtkWidget *viewarea; GtkWidget *view; GtkWidget *buffer; GtkTextBuffer *buffer; /* GtkTextBuffer doesn't inherit from GtkWidget! */ threads=NULL; g_thread_init (NULL); gdk_threads_init (); gtk_init(&argc, &argv); window=gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_signal_connect(GTK_OBJECT(window),"destroy", GTK_SIGNAL_FUNC(on_destroy),NULL); gtk_container_set_border_width(GTK_CONTAINER(window),10); vbox=gtk_vbox_new(FALSE,5); gtk_container_add(GTK_CONTAINER(window),vbox); gtk_widget_show(vbox); viewarea=gtk_scrolled_window_new(NULL,NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(viewarea), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_box_pack_start(GTK_BOX(vbox),viewarea,TRUE,TRUE,2); gtk_widget_show(viewarea); view=gtk_text_view_new(); buffer=gtk_text_view_get_buffer(GTK_TEXT_VIEW(view)); gtk_text_buffer_set_text(buffer,"The threads will write here.\n",-1); gtk_container_add(GTK_CONTAINER(viewarea),view); gtk_widget_show(view); button=gtk_button_new_with_label("Click
Re: GTK and threads
On Mon, 2006-02-06 at 11:22, Michael Torrie wrote: > I have attached a sample file that uses threads in the way you described > in your last post. I generally like to make code examples compile without warning. Did you even try to compile this? > #include > #include > #include > #include > #include #include /* sleep() - on Unix, anyway */ > gint thread_count=0; > gint dead_threads; > > GSList *threads; > > struct thread_info_data { > GtkTextBuffer *buffer; > gint id; > pthread_t tid; > gint terminate; > }; > > void thread (void *data) { void * thread(void *data) { > struct thread_info_data *info; > GtkTextIter iter; > GString *message; > > > info=(struct thread_info_data *)data; > message=g_string_new(""); > > while(info->terminate == 0 ) { > sleep(1); > g_string_printf(message,"Thread %d here.\n",info->id); > g_print("%s",message->str); > > gdk_threads_enter(); > gtk_text_buffer_get_end_iter(info->buffer,&iter); > gtk_text_buffer_insert(info->buffer,&iter,message->str,-1); > gdk_threads_leave(); > } > g_print("Thread %d stopping.\n",info->id); > gdk_threads_enter(); //borrowing a lock from gtk to lock our variable > dead_threads++; > gdk_threads_leave(); //we could and should use a counting semaphore > g_string_free(message,NULL); g_string_free(message,FALSE); /* Hope NULL means FALSE here */ return 0; > } > > void stop_thread(gpointer data, gpointer user_data) { > struct thread_info_data *thread; > > thread=data; > thread->terminate=1; > g_print("Asked thread %d to stop.\n",thread->id); > > //here we ought to make sure the thread really has died > //pthread_join(thread->tid,NULL); > } > > void on_destroy(GtkWidget *widget, gpointer data) { > g_slist_foreach(threads,stop_thread,NULL); > > while(dead_threads < thread_count) { > while(gtk_events_pending()) { > gtk_main_iteration(); > } > sleep(0); > } > gtk_main_quit(); > } > > void on_button_clicked(GtkWidget *widget, gpointer data) { > GtkTextBuffer *buffer; > GtkTextIter iter; > struct thread_info_data *thread_info; > > buffer=GTK_TEXT_BUFFER(data); > > thread_info=g_malloc(sizeof(struct thread_info_data)); > thread_info->buffer=buffer; > thread_info->id=thread_count++; > thread_info->terminate=0; > > threads=g_slist_append(threads,thread_info); > > pthread_create(&(thread_info->tid),NULL,thread,thread_info); > > > gtk_text_buffer_get_end_iter(buffer,&iter); > gtk_text_buffer_insert(buffer,&iter,"Button clicked!\n",-1); > g_print("Button clicked.\n"); > > > } > > > int main(int argc, char *argv[]) { > GtkWidget *window; > GtkWidget *button; > GtkWidget *vbox; > GtkWidget *viewarea; > GtkWidget *view; > GtkWidget *buffer; GtkTextBuffer *buffer; /* GtkTextBuffer doesn't inherit from GtkWidget! */ > threads=NULL; > > > g_thread_init (NULL); > gdk_threads_init (); > > gtk_init(&argc, &argv); > > window=gtk_window_new(GTK_WINDOW_TOPLEVEL); > > gtk_signal_connect(GTK_OBJECT(window),"destroy", > GTK_SIGNAL_FUNC(on_destroy),NULL); > gtk_container_set_border_width(GTK_CONTAINER(window),10); > > vbox=gtk_vbox_new(FALSE,5); > gtk_container_add(GTK_CONTAINER(window),vbox); > gtk_widget_show(vbox); > > viewarea=gtk_scrolled_window_new(NULL,NULL); > gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(viewarea), > GTK_POLICY_AUTOMATIC, > GTK_POLICY_AUTOMATIC); > gtk_box_pack_start(GTK_BOX(vbox),viewarea,TRUE,TRUE,2); > gtk_widget_show(viewarea); > > view=gtk_text_view_new(); > > buffer=gtk_text_view_get_buffer(GTK_TEXT_VIEW(view)); > > gtk_text_buffer_set_text(buffer,"The threads will write here.\n",-1); > gtk_container_add(GTK_CONTAINER(viewarea),view); > gtk_widget_show(view); > > button=gtk_button_new_with_label("Click me"); > gtk_signal_connect(GTK_OBJECT(button),"clicked", > GTK_SIGNAL_FUNC(on_button_clicked),buffer); > > gtk_box_pack_end(GTK_BOX(vbox),button,FALSE,FALSE,3); > > gtk_widget_show(button); > gtk_widget_show(window); > > gdk_threads_enter (); > gtk_main(); > gdk_threads_leave (); > > return 0; > } ___ gtk-app-devel-list mailing list gtk-app-devel-list@gnome.org http://mail.gno
RE: GTK and threads
How did you get an attachment to work with the list? I have never known that to work and often wished it would. -Original Message- From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] On Behalf Of Michael Torrie Sent: Monday, February 06, 2006 1:22 PM To: kornelix Cc: gtk app dev mail list Subject: Re: GTK and threads kornelix wrote: > Thanks. I eagerly anticipate your example. I have attached a sample file that uses threads in the way you described in your last post. The gui consists of a single text display and a button. When you click the button, a new thread is started that periodically (every second) sends a message to the text window. When you close the window, the program will send a signal to each thread to terminal (well not a real signal, just sets a flag). Once all the threads have terminated, the program ends. I have not implemented a proper signalling system to send signals to the threads nor have I used the pthread_join to properly rejoin threads that have quit. Mainly because pthread_join blocks and that causes problems. You'll notice the on_destroy callback has a loop that iterates the gtk event loop while we're waiting for the threads to stop. This is because we're in a callback, already holding the gdk_thread_lock, so any waiting in here will prevent threads from aquiring their lock and thus finishing their loops. So we iterate it. The callbacks (including the pthread_create calls) already occur in the context of the main gdk lock, so no explicit locking is needed there. See what you think. > > I made a small code example like the one you described. It hung up. Then > I figured out why: I am calling a function that has the > gdk_threads_enter() and _leave() wrappers from main() as well as from a > created thread. In the case of main(), the call to gdk_threads_enter() > was a second call for that thread, and this is apparently fatal. I have > to figure out how to detect and avoid this, or make multiple versions of > the functions with and without the wrappers. If I call the function from > the thread only, it works. > I really am not following what you are describing (please provide code) but it feels like you're definitely doing something wrong. It needn't be this complicated from my experience. > One way of looking at the issue is that the FAQ example includes all > main() code within the thread wrapper functions, meaning that any called > functions better not have the wrappers. Would it be legitimate to treat > main() like any other thread, and put the wrappers only around gtk/gdk > calls? If I could do this, then functions would be usable from both > main() and created threads. Hmm. Sounds complicated. My gut feeling is that most of your difficulties are in not knowing when you are in the gdk lock already and when you need to initiate a lock. Please tell me if my example code addresses any of the problems you have been having. (and for the real GTK experts out there, feel free to point out where I'm doing everything wrong.) Michael > > It will not take long, so I will just try this. > > regards > > > ___ gtk-app-devel-list mailing list gtk-app-devel-list@gnome.org http://mail.gnome.org/mailman/listinfo/gtk-app-devel-list
Re: GTK and threads
kornelix wrote: Thanks. I eagerly anticipate your example. I have attached a sample file that uses threads in the way you described in your last post. The gui consists of a single text display and a button. When you click the button, a new thread is started that periodically (every second) sends a message to the text window. When you close the window, the program will send a signal to each thread to terminal (well not a real signal, just sets a flag). Once all the threads have terminated, the program ends. I have not implemented a proper signalling system to send signals to the threads nor have I used the pthread_join to properly rejoin threads that have quit. Mainly because pthread_join blocks and that causes problems. You'll notice the on_destroy callback has a loop that iterates the gtk event loop while we're waiting for the threads to stop. This is because we're in a callback, already holding the gdk_thread_lock, so any waiting in here will prevent threads from aquiring their lock and thus finishing their loops. So we iterate it. The callbacks (including the pthread_create calls) already occur in the context of the main gdk lock, so no explicit locking is needed there. See what you think. I made a small code example like the one you described. It hung up. Then I figured out why: I am calling a function that has the gdk_threads_enter() and _leave() wrappers from main() as well as from a created thread. In the case of main(), the call to gdk_threads_enter() was a second call for that thread, and this is apparently fatal. I have to figure out how to detect and avoid this, or make multiple versions of the functions with and without the wrappers. If I call the function from the thread only, it works. I really am not following what you are describing (please provide code) but it feels like you're definitely doing something wrong. It needn't be this complicated from my experience. One way of looking at the issue is that the FAQ example includes all main() code within the thread wrapper functions, meaning that any called functions better not have the wrappers. Would it be legitimate to treat main() like any other thread, and put the wrappers only around gtk/gdk calls? If I could do this, then functions would be usable from both main() and created threads. Hmm. Sounds complicated. My gut feeling is that most of your difficulties are in not knowing when you are in the gdk lock already and when you need to initiate a lock. Please tell me if my example code addresses any of the problems you have been having. (and for the real GTK experts out there, feel free to point out where I'm doing everything wrong.) Michael It will not take long, so I will just try this. regards #include #include #include #include #include gint thread_count=0; gint dead_threads; GSList *threads; struct thread_info_data { GtkTextBuffer *buffer; gint id; pthread_t tid; gint terminate; }; void thread (void *data) { struct thread_info_data *info; GtkTextIter iter; GString *message; info=(struct thread_info_data *)data; message=g_string_new(""); while(info->terminate == 0 ) { sleep(1); g_string_printf(message,"Thread %d here.\n",info->id); g_print("%s",message->str); gdk_threads_enter(); gtk_text_buffer_get_end_iter(info->buffer,&iter); gtk_text_buffer_insert(info->buffer,&iter,message->str,-1); gdk_threads_leave(); } g_print("Thread %d stopping.\n",info->id); gdk_threads_enter(); //borrowing a lock from gtk to lock our variable dead_threads++; gdk_threads_leave(); //we could and should use a counting semaphore g_string_free(message,NULL); } void stop_thread(gpointer data, gpointer user_data) { struct thread_info_data *thread; thread=data; thread->terminate=1; g_print("Asked thread %d to stop.\n",thread->id); //here we ought to make sure the thread really has died // pthread_join(thread->tid,NULL); } void on_destroy(GtkWidget *widget, gpointer data) { g_slist_foreach(threads,stop_thread,NULL); while(dead_threads < thread_count) { while(gtk_events_pending()) { gtk_main_iteration(); } sleep(0); } gtk_main_quit(); } void on_button_clicked(GtkWidget *widget, gpointer data) { GtkTextBuffer *buffer; GtkTextIter iter; struct thread_info_data *thread_info; buffer=GTK_TEXT_BUFFER(data); thread_info=g_malloc(sizeof(struct thread_info_data)); thread_info->buffer=buffer; thread_info->id=thread_count++; thread_info->terminate=0; threads=g_slist_append(threads,thread_info);
Re: GTK and threads
This FAQ entry is where I started from. My first attempt at making threads work resulted in all threads running one after the other, in series instead of in parallel, because I was locking the whole thread with gdk_threads_enter() at the beginning. I "progressed" to trying to lock only the gtk/gdk calls in order to restore the parallelism. I am still trying to make it work, but creating bugs like the one I described earlier (two calls to gdk_threads_enter() in the same thread results in lockup). regards There's a FAQ entry about this: http://www.gtk.org/faq/#AEN482 And I'm pretty sure there's something very similar in the API documentation, but I don't feel like digging for it now. Bill Gates can rest quietly at night. The threat from Linux is only in the imagination of the Linux geeks. Please do not get angry. Shooting the messange is not the answer. I find it ironic that you say something so obviously inflammatory (and in this particular case, based on your incorrect assumptions), and then tell us not to get angry. If you don't want to get shot, then don't lace your message with thinly-veiled insults and accusations. -brian -BEGIN PGP SIGNATURE- Version: GnuPG v1.4.2 (GNU/Linux) iD8DBQFD5xdX6XyW6VEeAnsRAmEKAJ9SSSNmiki90556Um3bCusQ8BX83wCgulr5 9J/8Ggqq5GV8hsdD8C5CLQE= =LZO0 -END PGP SIGNATURE- ___ gtk-app-devel-list mailing list gtk-app-devel-list@gnome.org http://mail.gnome.org/mailman/listinfo/gtk-app-devel-list ___ gtk-app-devel-list mailing list gtk-app-devel-list@gnome.org http://mail.gnome.org/mailman/listinfo/gtk-app-devel-list
Re: GTK and threads
OK, I see. That was illuminating, but not the whole story. In Win32, you can send messages to a window to make it update from its paint() function in its owning thread, or you can write directly to it from another thread, if you have its handle. I went and found an old code fragment from a graphic application I wrote about 1995: SelectObject(hDC,hColorBrush[ii]); // draw in color PatBlt(hDC,ipx,ipy,xw,yw,PATCOPY); hDC is a handle to a "device context", basically a window pointer. The above code runs in a thread that did not create the window. No explicit locks are evident. The point here was speed: screen updates were much faster this way compared to waiting for the paint() function to run after invalidating a portion of the window. My memory of win32 is old but I think the above is correct. I am sure your points are also correct. regards Tor Lillqvist wrote: kornelix writes: > I hope you will indulge me. I don't recall any counterparts in > Win32 to these wrapper functions (gtk/gdk init / enter / leave). > Perhaps I am off base, but I think Win32 takes care of its own > locking and threading business. Well, surprise, as far as I know, it doesn't. For instance an utterly trivial-looking Win32 API like SetWindowText() doesn't directly manipulate the window's title. It sends a message to the thread that owns (created) the window in question. If the window was created from another thread, that doesn't have a message pump (isn't waiting to handle Windows messages most of the time), but for instance is another random "worker" thread that you just happened to create a window from, you will have fun. You don't need to google for long to find articles with statements like: You get the assertions because MFC does not permit you to access most CWnd functions from a thread that did not create the window. The assertions are a warning that you are attempting an unsafe operation because the MFC message routing code is not thread safe. And that is just an example, written by somebody who says he is a VC++ MVP, so presumably knows what he is talking about. The article quoted above is from 2002, so of course, it might be that I am completely wrong here, and that some very new MFC version actually is all-singing all-dancing multi-thread-transparent where user code can do anything it wants from any thread, like you say. On the other hand, that doesn't seem likely, as MFC is much on its way out, isn't it, considering the intended future with managed code, Windows.Forms and whatnot? > One of you mentioned that X11 has no thread awareness in its user > (caller) protocol. Sounds great to me. Was this a criticism? No, on the contrary. I mentioned it as a comparison to the Win32 windowing and graphics API, which isn't based on a network protocol, and where thread dependencies are very much built-in (which makes it much harder for a toolkit running on top of it to support multi-threadedness). > Sadly this is the typical state of documentation for Linux and most > open-source software. If you feel like that, it's great opportunity for you to help, isn't it? --tml ___ gtk-app-devel-list mailing list gtk-app-devel-list@gnome.org http://mail.gnome.org/mailman/listinfo/gtk-app-devel-list ___ gtk-app-devel-list mailing list gtk-app-devel-list@gnome.org http://mail.gnome.org/mailman/listinfo/gtk-app-devel-list
Re: GTK and threads
Thanks. I eagerly anticipate your example. I made a small code example like the one you described. It hung up. Then I figured out why: I am calling a function that has the gdk_threads_enter() and _leave() wrappers from main() as well as from a created thread. In the case of main(), the call to gdk_threads_enter() was a second call for that thread, and this is apparently fatal. I have to figure out how to detect and avoid this, or make multiple versions of the functions with and without the wrappers. If I call the function from the thread only, it works. One way of looking at the issue is that the FAQ example includes all main() code within the thread wrapper functions, meaning that any called functions better not have the wrappers. Would it be legitimate to treat main() like any other thread, and put the wrappers only around gtk/gdk calls? If I could do this, then functions would be usable from both main() and created threads. It will not take long, so I will just try this. regards Michael Torrie wrote: kornelix wrote: Thanks to the three of you for your help and information. I will continue trying to make GTK work for my threaded application, and post progress (or lack thereof). I am still confused (by apparently conflicting inputs from the GTK FAQ and yourselves) about when I must use which wrapper calls to force the GDK/GTK functions to single-thread themselves. First, is there a distinction between the main() thread and threads created later with pthread_create(), or should I be following the same rules? I have been making a distinction, and I am thinking this must be wrong. Posting some code is a good start. I think that the only way to get this solved is to have a complete working (or non-working), compilable source code snippet that illustrates very simply what you are trying to do. Then we can identify the problems. I myself am not experienced enough to deduce the problems solely from the code snippets you have below. To this end later today I will build a very small C program that I believe will illustrate what you are trying to accomplish. I will have a simple button that, upon clicking, will spawn a thread that will just do something simple, like writing text to the window or something. Yes the documentation for GTK is lacking in some areas (like the proper ways to do threading and things). However there are many, many good source code examples out there of projects large and small that do work. Anyway, I will post my example code and findings later today. Michael The rules as I understand them now: Main program: g_thread_init(NULL); gdk_threads_init(); gtk_init(&argc, &argv); ... gdk_threads_enter(); // I had omitted this step win = gtk_window_new(...); ... add some menus to win gtk_widget_show_all(win); gtk_main(); gdk_threads_leave(); menu event function: pthread_create() a response thread menu response thread: every GTK/GDK function wrapped as follows: gdk_threads_enter(); ... do GTK calls to create / update windows and / or get user input gdk_flush(); gdk_threads_leave(); Signal response functions: always in main() thread, without enter/leave wrapper calls. Some Glib functions (e.g. idle, timeout): always in main() thread, with enter/leave wrappers. (I am not using these, so I can live with the ambiguity for now). Now I am going to harangue you once again about the need for all the above stuff. I hope you will indulge me. I don't recall any counterparts in Win32 to these wrapper functions (gtk/gdk init / enter / leave). Perhaps I am off base, but I think Win32 takes care of its own locking and threading business. I still think GTK should do the same. The GTK user (caller) should not have to single-thread the functions by putting wrappers around the calls. The above rules are simply awful. If GTK must single-thread (some of) its function calls, it should manage this itself. I have been advised several times to move all GTK calls into the main() thread and keep them out of the created threads. I hope this is not the answer, because this makes the application much more complex. For a simple example: I want to write text to a logging window from multiple threads. I wrote a simple function to do this that works like printf(). To avoid GTK calls from the threads, I would have to create a queue of such messages and have an idle function in main() that checks the queue and updates the window, or (better), have the thread functions send a message to the logging window and have its event function take care of the updates. For more complex cases, e.g. graphic updates or user dialogs, it just gets messier. Am I failing to understand something here? One of you mentioned that X11 has no thread awareness in its user (caller) protocol. Sounds great to me. Was this a criticism? The lockup problem I mentioned was definitely GTK. It w
Re: GTK and threads
kornelix wrote: Thanks to the three of you for your help and information. I will continue trying to make GTK work for my threaded application, and post progress (or lack thereof). I am still confused (by apparently conflicting inputs from the GTK FAQ and yourselves) about when I must use which wrapper calls to force the GDK/GTK functions to single-thread themselves. First, is there a distinction between the main() thread and threads created later with pthread_create(), or should I be following the same rules? I have been making a distinction, and I am thinking this must be wrong. Posting some code is a good start. I think that the only way to get this solved is to have a complete working (or non-working), compilable source code snippet that illustrates very simply what you are trying to do. Then we can identify the problems. I myself am not experienced enough to deduce the problems solely from the code snippets you have below. To this end later today I will build a very small C program that I believe will illustrate what you are trying to accomplish. I will have a simple button that, upon clicking, will spawn a thread that will just do something simple, like writing text to the window or something. Yes the documentation for GTK is lacking in some areas (like the proper ways to do threading and things). However there are many, many good source code examples out there of projects large and small that do work. Anyway, I will post my example code and findings later today. Michael The rules as I understand them now: Main program: g_thread_init(NULL); gdk_threads_init(); gtk_init(&argc, &argv); ... gdk_threads_enter(); // I had omitted this step win = gtk_window_new(...); ... add some menus to win gtk_widget_show_all(win); gtk_main(); gdk_threads_leave(); menu event function: pthread_create() a response thread menu response thread: every GTK/GDK function wrapped as follows: gdk_threads_enter(); ... do GTK calls to create / update windows and / or get user input gdk_flush(); gdk_threads_leave(); Signal response functions: always in main() thread, without enter/leave wrapper calls. Some Glib functions (e.g. idle, timeout): always in main() thread, with enter/leave wrappers. (I am not using these, so I can live with the ambiguity for now). Now I am going to harangue you once again about the need for all the above stuff. I hope you will indulge me. I don't recall any counterparts in Win32 to these wrapper functions (gtk/gdk init / enter / leave). Perhaps I am off base, but I think Win32 takes care of its own locking and threading business. I still think GTK should do the same. The GTK user (caller) should not have to single-thread the functions by putting wrappers around the calls. The above rules are simply awful. If GTK must single-thread (some of) its function calls, it should manage this itself. I have been advised several times to move all GTK calls into the main() thread and keep them out of the created threads. I hope this is not the answer, because this makes the application much more complex. For a simple example: I want to write text to a logging window from multiple threads. I wrote a simple function to do this that works like printf(). To avoid GTK calls from the threads, I would have to create a queue of such messages and have an idle function in main() that checks the queue and updates the window, or (better), have the thread functions send a message to the logging window and have its event function take care of the updates. For more complex cases, e.g. graphic updates or user dialogs, it just gets messier. Am I failing to understand something here? One of you mentioned that X11 has no thread awareness in its user (caller) protocol. Sounds great to me. Was this a criticism? The lockup problem I mentioned was definitely GTK. It was repeatable: I started my (faulty) GTK app, selected a menu causing a thread creation with GTK calls, and the whole GNOME desktop froze up. Nothing worked at all, not even a terminal launch from the panel. I had to power off. IIRC, it was the situation depicted above with the missing call to gtk_threads_enter(). << You're looking at this in an overly-complicated way. Here are a few guidelines, all of which probably have appropriate documentation somewhere: ... >> Sadly this is the typical state of documentation for Linux and most open-source software. The insider gurus and macho-geeks don't need the documentation, therefore it does not exist, is outdated, is scattered and disorganized, or just wrong. When web forums and e-mail lists are the only support you get, then quality documentation is of the utmost importance. Bill Gates can rest quietly at night. The threat from Linux is only in the imagination of the Linux geeks. Please do not get angry. Shooting the messange is not the answer. I am an old Windows progra
Re: GTK and threads
kornelix writes: > I hope you will indulge me. I don't recall any counterparts in > Win32 to these wrapper functions (gtk/gdk init / enter / leave). > Perhaps I am off base, but I think Win32 takes care of its own > locking and threading business. Well, surprise, as far as I know, it doesn't. For instance an utterly trivial-looking Win32 API like SetWindowText() doesn't directly manipulate the window's title. It sends a message to the thread that owns (created) the window in question. If the window was created from another thread, that doesn't have a message pump (isn't waiting to handle Windows messages most of the time), but for instance is another random "worker" thread that you just happened to create a window from, you will have fun. You don't need to google for long to find articles with statements like: You get the assertions because MFC does not permit you to access most CWnd functions from a thread that did not create the window. The assertions are a warning that you are attempting an unsafe operation because the MFC message routing code is not thread safe. And that is just an example, written by somebody who says he is a VC++ MVP, so presumably knows what he is talking about. The article quoted above is from 2002, so of course, it might be that I am completely wrong here, and that some very new MFC version actually is all-singing all-dancing multi-thread-transparent where user code can do anything it wants from any thread, like you say. On the other hand, that doesn't seem likely, as MFC is much on its way out, isn't it, considering the intended future with managed code, Windows.Forms and whatnot? > One of you mentioned that X11 has no thread awareness in its user > (caller) protocol. Sounds great to me. Was this a criticism? No, on the contrary. I mentioned it as a comparison to the Win32 windowing and graphics API, which isn't based on a network protocol, and where thread dependencies are very much built-in (which makes it much harder for a toolkit running on top of it to support multi-threadedness). > Sadly this is the typical state of documentation for Linux and most > open-source software. If you feel like that, it's great opportunity for you to help, isn't it? --tml ___ gtk-app-devel-list mailing list gtk-app-devel-list@gnome.org http://mail.gnome.org/mailman/listinfo/gtk-app-devel-list
Re: GTK and threads
-BEGIN PGP SIGNED MESSAGE- Hash: SHA1 kornelix wrote: > Brian J. Tarricone wrote: > >> You're looking at this in an overly-complicated way. Here are a few >> guidelines, all of which probably have appropriate documentation >> somewhere: ... > > Sadly this is the typical state of documentation for Linux and most > open-source software. The insider gurus and macho-geeks don't need the > documentation, therefore it does not exist, is outdated, is scattered > and disorganized, or just wrong. When web forums and e-mail lists are > the only support you get, then quality documentation is of the utmost > importance. There's a FAQ entry about this: http://www.gtk.org/faq/#AEN482 And I'm pretty sure there's something very similar in the API documentation, but I don't feel like digging for it now. > Bill Gates can rest quietly at night. The threat from Linux > is only in the imagination of the Linux geeks. > Please do not get angry. Shooting the messange is not the answer. I find it ironic that you say something so obviously inflammatory (and in this particular case, based on your incorrect assumptions), and then tell us not to get angry. If you don't want to get shot, then don't lace your message with thinly-veiled insults and accusations. -brian -BEGIN PGP SIGNATURE- Version: GnuPG v1.4.2 (GNU/Linux) iD8DBQFD5xdX6XyW6VEeAnsRAmEKAJ9SSSNmiki90556Um3bCusQ8BX83wCgulr5 9J/8Ggqq5GV8hsdD8C5CLQE= =LZO0 -END PGP SIGNATURE- ___ gtk-app-devel-list mailing list gtk-app-devel-list@gnome.org http://mail.gnome.org/mailman/listinfo/gtk-app-devel-list
GTK and threads
Thanks to the three of you for your help and information. I will continue trying to make GTK work for my threaded application, and post progress (or lack thereof). I am still confused (by apparently conflicting inputs from the GTK FAQ and yourselves) about when I must use which wrapper calls to force the GDK/GTK functions to single-thread themselves. First, is there a distinction between the main() thread and threads created later with pthread_create(), or should I be following the same rules? I have been making a distinction, and I am thinking this must be wrong. The rules as I understand them now: Main program: g_thread_init(NULL); gdk_threads_init(); gtk_init(&argc, &argv); ... gdk_threads_enter(); // I had omitted this step win = gtk_window_new(...); ... add some menus to win gtk_widget_show_all(win); gtk_main(); gdk_threads_leave(); menu event function: pthread_create() a response thread menu response thread: every GTK/GDK function wrapped as follows: gdk_threads_enter(); ... do GTK calls to create / update windows and / or get user input gdk_flush(); gdk_threads_leave(); Signal response functions: always in main() thread, without enter/leave wrapper calls. Some Glib functions (e.g. idle, timeout): always in main() thread, with enter/leave wrappers. (I am not using these, so I can live with the ambiguity for now). Now I am going to harangue you once again about the need for all the above stuff. I hope you will indulge me. I don't recall any counterparts in Win32 to these wrapper functions (gtk/gdk init / enter / leave). Perhaps I am off base, but I think Win32 takes care of its own locking and threading business. I still think GTK should do the same. The GTK user (caller) should not have to single-thread the functions by putting wrappers around the calls. The above rules are simply awful. If GTK must single-thread (some of) its function calls, it should manage this itself. I have been advised several times to move all GTK calls into the main() thread and keep them out of the created threads. I hope this is not the answer, because this makes the application much more complex. For a simple example: I want to write text to a logging window from multiple threads. I wrote a simple function to do this that works like printf(). To avoid GTK calls from the threads, I would have to create a queue of such messages and have an idle function in main() that checks the queue and updates the window, or (better), have the thread functions send a message to the logging window and have its event function take care of the updates. For more complex cases, e.g. graphic updates or user dialogs, it just gets messier. Am I failing to understand something here? One of you mentioned that X11 has no thread awareness in its user (caller) protocol. Sounds great to me. Was this a criticism? The lockup problem I mentioned was definitely GTK. It was repeatable: I started my (faulty) GTK app, selected a menu causing a thread creation with GTK calls, and the whole GNOME desktop froze up. Nothing worked at all, not even a terminal launch from the panel. I had to power off. IIRC, it was the situation depicted above with the missing call to gtk_threads_enter(). << You're looking at this in an overly-complicated way. Here are a few guidelines, all of which probably have appropriate documentation somewhere: ... >> Sadly this is the typical state of documentation for Linux and most open-source software. The insider gurus and macho-geeks don't need the documentation, therefore it does not exist, is outdated, is scattered and disorganized, or just wrong. When web forums and e-mail lists are the only support you get, then quality documentation is of the utmost importance. Bill Gates can rest quietly at night. The threat from Linux is only in the imagination of the Linux geeks. Please do not get angry. Shooting the messange is not the answer. I am an old Windows programmer trying to change his spots. I am no Microsoft fan, and I hope you Linux / open-source geeks can put some brakes on the bullying monopoly. I am fairly geeky myself, but still an infant in the Linux arena, and very grateful for all the help I can get. regards ___ gtk-app-devel-list mailing list gtk-app-devel-list@gnome.org http://mail.gnome.org/mailman/listinfo/gtk-app-devel-list