[Gtk-sharp-list] Gtk.DrawingArea not thread-agnostic on Win32?

Sam Hocevar sam at zoy.org
Tue Sep 23 06:00:09 EDT 2008


   I have a threaded GTK# application that creates widgets in several
threads (all with proper synchronisation, of course). It works perfectly
on Linux, but it hangs on Win32 when using Gtk.DrawingArea objects.

   Attached is a sample program which does the following:
     - thread #1 creates a Gtk.Window
     - thread #1 spawns thread #2
     - thread #2 creates a Gtk.DrawingArea object
     - thread #1 attaches the DrawingArea to the Window
     - thread #1 waits for user input
     - thread #2 destroys the Gtk.DrawingArea object
     - thread #1 joins thread #2
     - thread #1 exits

   Everything goes well on Linux. On Win32, the program hangs during the
Gtk.DrawingArea destruction.

   It should be noted that using Gtk.Button instead of Gtk.DrawingArea
makes everything work properly on both Linux and Windows.

   Any ideas on what may be wrong?

Cheers,
-- 
Sam.
-------------- next part --------------

using System;
using System.Threading;
using Gtk;
using Gdk;

namespace Program
{
    class My
    {
        public static void Debug(object msg)
        {
            Console.WriteLine("Thread [{1}]: {0}", msg,
                  System.Threading.Thread.CurrentThread.GetHashCode());
        }
    }


    class Draw : Gtk.DrawingArea
    {
        public Draw()
        {
             My.Debug("creating DrawingArea");
        }


        protected override bool OnDeleteEvent(Event evnt)
        {
            My.Debug("DrawingArea deleted (should never be called)");
            return base.OnDeleteEvent(evnt);
        }


        protected override void OnDestroyed()
        {
            My.Debug("DrawingArea destroyed");
            base.OnDestroyed();
        }
    }


    class Win : Gtk.Window
    {
        private Draw _darea = null;
        private Thread _thread;
        private bool _running = false;


        public Win(string title) : base(title)
        {
            My.Debug("creating Window");

            // Launch the parallel thread
            Gdk.Threads.Leave();
            _thread = new Thread(threadFunc);
            _thread.Start();
            Gdk.Threads.Enter();

            // Wait until the object is created
            while(_darea == null)
            {
                Gdk.Threads.Leave();
                My.Debug("waiting for DrawingArea creation");
                Thread.Sleep(5);
                Gdk.Threads.Enter();
            }

            Gtk.VBox box = new VBox();

            My.Debug("attaching DrawingArea");
            box.Add(_darea);

            Gtk.Button quit = new Gtk.Button("Quit");
            quit.Clicked += ClickQuit;
            box.Add(quit);

            Add(box);
        }


        private void threadFunc()
        {
            My.Debug("thread started");

            Gdk.Threads.Enter();
            _darea = new Draw();
            _darea.SetSizeRequest(400, 300);
            _running = true;
            Gdk.Threads.Leave();

            My.Debug("sleeping");

            while(_running)
            {
                Thread.Sleep(10);
            }

            My.Debug("destroying DrawingArea");

            Gdk.Threads.Enter();
            _darea.Destroy();
            Gdk.Threads.Leave();

            My.Debug("thread ended");
        }


        private void Quit()
        {
            _running = false;
            Gdk.Threads.Leave();
            _thread.Join();
            Gdk.Threads.Enter();

            My.Debug("quitting application");
            Application.Quit();
        }


        private void ClickQuit(object o, EventArgs e)
        {
            My.Debug("quit clicked");
            Quit();
        }


        protected override bool OnDeleteEvent(Event evnt)
        {
            My.Debug("Window deleted");
            Quit();
            return base.OnDeleteEvent(evnt);
        }


        protected override void OnDestroyed()
        {
            My.Debug("Window destroyed");
            base.OnDestroyed();
        }
    }

    public class Program
    {
        public static int Main(string[] args)
        {
            My.Debug("starting program");

            if (!GLib.Thread.Supported)
                GLib.Thread.Init();
            Gdk.Threads.Init();
            Gdk.Threads.Enter();

            Application.Init();
            Win win = new Win("Program");
            win.ShowAll();

            My.Debug("entering GTK loop");
            Application.Run();

            Gdk.Threads.Leave();

            My.Debug("ending program");
            return 0;
        }
    }
}



More information about the Gtk-sharp-list mailing list