GNOME Bugzilla – Bug 60620
GTK on Win32 can not be used from multiple threads
Last modified: 2009-04-29 22:52:47 UTC
I found gdk_window_clear_area() (in gdkwindow-win32.c) is not thread-safe. I think Win32API "SendMessage()" is not suitable for multi-thread program.
Created attachment 5612 [details] sample source program
Fixed in gtk-1-3-win32-production branch in CVS. Corresponding fix presumably needs to be applied to HEAD also. * gdk/win32/gdkprivate-win32.h (struct _GdkWindowWin32Data): Add owner thread id. * gdk/win32/gdkwindow-win32.c (gdk_window_clear_area): Instead of calling sending WM_ERASEBKGND to the window, call the window procedure directly. Clean out the #if 0 cruft. * gdk/win32/gdkdrawable-win32.c (gdk_win32_draw_drawable): If the window is owned by another thread, don't call UpdateWindow(), but post WM_PAINT to the thread.
I tested again with the fixed version (in gtk-1-3-win32-production branch), and I found another bug. Deadlock is occurred in gdkwindow-win32.c#831 (Win32API "MoveWindow" is called from "gdk_window_move").
Sample source for the gdk_window_move problem?
Created attachment 5972 [details] This is a sample program which causes a deadlock in Win32API "MoveWindow()".
IMO there are many places where Gdk/win32 isn't thread-safe. - Almost every api call like MoveWindow, ShowWindow etc. will probably break if it gets called from a different thread than the windows owner - I'm not sure if - but expecting, that - the same problem does exist for Gtk in general. AFAIK GObjects are thread-safe if used from _one_ thread. Simply accessing them from another thread does require locking done by the user - The message mapping from win32->Gdk will break with Gdk windows living in different threads, because PeekMessage () does see only message in the calling thread - Luckily there seem to be almost no Gtk apps really reqiring GUI threads ... (as always, patches are welcome but IMHO here some kind of design documents need to come first)
See thread at: http://mail.gnome.org/archives/gtk-devel-list/2001-November/msg00227.html I'm putting this on the 2.0.0 milestone, but I suspect that might not be realistic, since fixing this would require some fancy reworking of how event handling is done.
Putting win32 bugs on 2.2.0 milestone, since we don't plan on having win32 official for the 2.0.x branch.
I think work on making the Win32 backend MT-safe will have to wait rather long (unless somebody contributes patches).
Here is a small program that works on X11 and not on win32: The window disappears immediatly when the thread finishes, and if the thread is kept alive (uncomment "sleep"), the window is frozen. -----------test.c-------------------- #include <gtk/gtk.h> GtkWidget *window; GtkWidget *label; GThread *thread; gint function() { gdk_threads_enter(); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); label=gtk_label_new("my text"); gtk_container_add(GTK_CONTAINER(window), label); gtk_widget_realize(window); gtk_widget_show_all(window); gdk_threads_leave(); //sleep(10000); } gint main(int argc, char *argv[]) { g_thread_init (NULL); gdk_threads_init(); gtk_init(&argc,&argv); thread = g_thread_create((GThreadFunc)function, NULL, TRUE, NULL); g_thread_join(thread); gdk_threads_enter(); gtk_main(); gdk_threads_leave(); } -------------------------------------------- compiled on MinGW with: gcc -g -DDEBUG -mms-bitfields -mwindows `pkg-config --cflags gtk+-2.0` -c test.c -o test.od gcc -static -mms-bitfields -mwindows -o test.exe test.od `pkg-config --libs g tk+-2.0 --libs gthread-2.0` -L/lib -------------------------------------------- This kind of window creation is useful when a thread wants to notify something in a popup window. (For example a progress bar.)
*** Bug 155038 has been marked as a duplicate of this bug. ***
Thank you all for your precisions, but now i'm afraid that i won't be able to run my app under Windows ... Is there any possibility to encourage the development of an alternative that could permit multi-thread on Windows with GTK ? Maybe could i participate to the development if it is necessary ? I'm motivated PS : don't pay attention to my English i'm French ;)
Basically, the approach that has been discussed is to use a server thread to create windows and take events. If you are interested in this area, you might want to get into touch with Tod Fischer <taf2@lehigh.edu>, who started looking into doing the work and maybe John Ehresman <jpe@wingide.com> who had some good ideas when we were discussing this on IRC.
Errr, that's Todd Fisher, sorry for the mispellings.
Created attachment 32521 [details] IRC conversation on issue
Yes, the IRC conversion brings up all the relevant issues, I think. A separate thread that handles all window creation and message processing is what I have been thinking of, too. Whether all drawing needs to be handled by this thread, too, I don't know. Possibly. At least it might be that handling drawing, too, in the GUI thread would mean less synchronization problems. I have a vague feeling that to implement the calls from user threads into the GUI thread it might be a good idea to use the "user-mode asynchronous procedure call" stuff. See MSDN or Platform SDK docs for QueueUserAPC() and APCProc().
Thank you Owen for your informations ... i'll be more often on the IRC GTK+ channel now. I have seen a product named GPK (General Proxy Kit) which is permitting GTK thread-safe acces but only on X11 system and for GTK version 0.9 and before 1.2. But I think we could inspirate us from its fonctionnalities to build a Win32 GPK for GTK 2.0. And maybe could we use some of its code ...
"Errr, that's Todd Fisher, sorry for the mispellings." Also, my e-mail address has changed since I graduated college it is now toddf@simosoftware.com.
Please could this little gotcha be mentioned in the GDK Reference Manual. It took me a while to track down how an apparently innocuous gtk_list_store_append ended up blocking inside the win32 API.
Note added to gtk-2-8 and HEAD: 2006-04-04 Tor Lillqvist <tml@novell.com> * gdk/tmpl/threads.sgml: Mention that the Win32 backend should not be used from multiple threads.
I think this can safely be closed as WONTFIX...
Sad :-(
To get around this, I wrote a few lines of code to allow different threads execute code in the main thread. (I did not want to completely redesign my app...) Just thought it might be useful to somebody. You can either pass a GClosure or use a more convenient, GThreadFunc-like version.
Created attachment 67577 [details] thread-guard.c (workaround, see comment)
Created attachment 67578 [details] thread-guard.h (workaround, see comment)
Thanks! Could you also attach some simple minimal sample application that uses your thread-guard stuff?
Created attachment 67585 [details] thread-guard-sample.c (sample usage for thread-guard)
What I forgot to mention before: For thread-guard you also have to create a file marshallers.in with the following contents: POINTER:VOID and generate the according C files by running $ glib-genmarshal --header marshallers.in > marshallers.h $ glib-genmarshal --body marshallers.in > marshallers.c I hope the comments in thread-guard-sample.c are understandable for most developers. When all files reside in one directory, compiling looks like $ gcc $(pkg-config --cflags --libs gtk+-2.0 gthread-2.0) -o thread-guard-sample thread-guard-sample.c thread-guard.c marshallers.c May it simplify or complicate your Win32 programming :)
I don't think the suggestion for such a facility should be on this bug; it has no direct relevance to Win32 or GTK+ when you come down to it. It might be a reasonable GLib API addition. (It would be considerably simpler to use a GSource per callback, like g_idle_add() g_timeout_add(), or just use g_idle_add() internally.)
Created attachment 67623 [details] Example of performing a synchronous call in the main thread In your example you need to handle the gdk lock more carefully and you do not have a situtation where you require a synchronous call - as opposed to just defering the work to an idle handler. From an application point of view you may find the attached example useful.
is there any chance this bug could be reopened? I was planning on using pygtk and cairo to build a 2d drawing library for a graphics programming class, and one of the key features is that students will be able to interactively examine and update their drawing apps from the python shell. Having gtk lock up the main interactive thread is unacceptable for my project and I am considering dropping gtk and using something else. this works great in linux, and a solution seems to have been proposed for windows, why wasn't it implemented? if the problem is just that no one got around to doing it I would be willing to help.
I think that if an implementation appeared and worked well, it would be seriously considered. That said, it's a big job once you consider all the debugging that will likely be needed. I suspect you'd have an easier time modifying your app to work with a single display thread. The question isn't really reopening the bug, it's whether someone or group of people can come up with an implementation.
*** Bug 388304 has been marked as a duplicate of this bug. ***
*** Bug 537859 has been marked as a duplicate of this bug. ***
*** Bug 580800 has been marked as a duplicate of this bug. ***