[Gtk-sharp-list] Main thread unref patch.

Miguel de Icaza miguel@ximian.com
11 Mar 2003 18:19:29 -0500


--=-peueodkuHa2tkX36niZt
Content-Type: text/plain
Content-Transfer-Encoding: 7bit

Hello,

    Since Destructors (they should really be called finalizers) will be
invoked from a thread, and since Gtk+ is not thread safe, we should only
invoke unref() from the Gtk main thread.

    The following patch queues objects for destruction on Dispose, and
queues and Idle handler to perform the destructions in the context of
the main thread.

Miguel.

--=-peueodkuHa2tkX36niZt
Content-Disposition: attachment; filename=thread.patch
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; name=thread.patch; charset=ISO-8859-1

? thread.patch
Index: Idle.cs
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvs/public/gtk-sharp/glib/Idle.cs,v
retrieving revision 1.2
diff -u -u -r1.2 Idle.cs
--- Idle.cs	22 Feb 2003 04:34:55 -0000	1.2
+++ Idle.cs	11 Mar 2003 23:20:41 -0000
@@ -33,6 +33,10 @@
=20
 	public class Idle {
=20
+		private Idle ()
+		{
+		}
+	=09
 		[DllImport("libglib-2.0-0.dll")]
 		static extern uint g_idle_add (IdleHandler d, IntPtr data);
=20
Index: Object.cs
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvs/public/gtk-sharp/glib/Object.cs,v
retrieving revision 1.41
diff -u -u -r1.41 Object.cs
--- Object.cs	24 Feb 2003 06:39:29 -0000	1.41
+++ Object.cs	11 Mar 2003 23:20:41 -0000
@@ -4,7 +4,10 @@
 //	    Mike Kestner <mkestner@speakeasy.net>
 //
 // (c) 2001 Bob Smith and Mike Kestner
-
+//
+// TODO:
+//   Could remove `disposed' for a check if an object is on the dispose_qu=
eue_list.
+//
 namespace GLib {
=20
 	using System;
@@ -36,12 +39,42 @@
 		bool disposed =3D false;
 		Hashtable Data;
 		static Hashtable Objects =3D new Hashtable();
+		static Queue PendingDestroys =3D new Queue ();
+		static bool idle_queued;
=20
+		//
+		// The destructor is invoked by a thread
+		//
 		~Object ()
 		{
 			Dispose ();
 		}
=20
+		static bool PerformQueuedUnrefs ()
+		{
+			Object [] objects;
+
+			Console.WriteLine ("Perfoming dequeuing for {0} at {1}", PendingDestroy=
s.Count, AppDomain.GetCurrentThreadId ());
+		=09
+			lock (PendingDestroys){
+				objects =3D new Object [PendingDestroys.Count];
+				PendingDestroys.CopyTo (objects, 0);
+				PendingDestroys.Clear ();
+			}
+			lock (typeof (Object))
+				idle_queued =3D false;
+
+			foreach (Object o in objects){
+				if (o._obj =3D=3D IntPtr.Zero)
+					continue;
+			=09
+				Objects.Remove (o._obj);
+				o.Unref ();
+				o._obj =3D IntPtr.Zero;
+			}
+			return false;
+		}
+
 		/// <summary>
 		///	Dispose Method=20
 		/// </summary>
@@ -57,8 +90,17 @@
 			if (disposed)
 				return;
=20
-			DisposeNative ();
 			disposed =3D true;
+			lock (PendingDestroys){
+				PendingDestroys.Enqueue (this);
+				lock (typeof (Object)){
+					if (!idle_queued){
+						Idle.Add (new IdleHandler (PerformQueuedUnrefs));
+						idle_queued =3D true;
+					}
+				}
+			}
+			GC.SuppressFinalize (this);
 		}
=20
 		[DllImport("libgobject-2.0-0.dll")]
@@ -66,14 +108,6 @@
 	=09
 		protected virtual void DisposeNative ()
 		{
-			if (_obj =3D=3D IntPtr.Zero)
-				return;
-
-			Objects.Remove (Raw);
-
-			GC.SuppressFinalize (this);
-			g_object_unref (_obj);
-			_obj =3D IntPtr.Zero;
 		}
=20
 		[DllImport("libgobject-2.0-0.dll")]
@@ -104,6 +138,8 @@
 		///   Decreases the reference count on the native object.
 		///   This method is used by generated classes and structs,
 		///   and should not be used in user code.
+		///
+		///   This method should not be invoked by a thread.
 		/// </remarks>
 		public virtual void Unref ()
 		{

--=-peueodkuHa2tkX36niZt--