changeset 100:673947ce458a v2

added multithreading support to Disposable class
author cin
date Wed, 05 Nov 2014 16:39:56 +0300
parents 8ddf1648eca4
children 279e226dffdd
files Implab/Disposable.cs
diffstat 1 files changed, 60 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/Implab/Disposable.cs	Wed Nov 05 02:31:35 2014 +0300
+++ b/Implab/Disposable.cs	Wed Nov 05 16:39:56 2014 +0300
@@ -1,9 +1,7 @@
 using Implab.Diagnostics;
 using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Linq;
-using System.Web;
+using System.Threading;
+using System.IO;
 
 namespace Implab {
     /// <summary>
@@ -11,40 +9,84 @@
     /// </summary>
     public class Disposable : IDisposable {
         
-        bool m_disposed;
+        int m_disposed;
 
         public event EventHandler Disposed;
 
         public bool IsDisposed {
-            get { return m_disposed; }
+            get {
+                Thread.MemoryBarrier();
+                return m_disposed != 0;
+            }
         }
 
+        /// <summary>
+        /// Asserts the object is not disposed.
+        /// </summary>
+        /// <exception cref="ObjectDisposedException">The object is disposed</exception>
+        /// <remarks>
+        /// Успешная проверка того, что объект не освобожден еще не гарантирует, что он не
+        /// будет освобожден сразу после нее, поэтому методы использующие проверку должны
+        /// учитывать, что объект может быть освобожден из параллельного потока.
+        /// Данны метод служит для упрощения отладки ошибок при использовании объекта после его
+        /// освобождения.
+        /// </remarks>
+        /// <example>
+        /// // пример синхронизированного освобождения ресурсов
+        /// class FileStore : Disposable {
+        ///     readonly TextWriter m_file;
+        ///     readonly obejct m_sync = new object();
+        /// 
+        ///     public FileStore(string file) {
+        ///         m_file = new TextWriter(File.OpenWrite(file));
+        ///     }
+        /// 
+        ///     public void Write(string text) {
+        ///         lock(m_sync) {
+        ///             AssertNotDisposed();
+        ///             m_file.Write(text);
+        ///         }
+        ///     }
+        /// 
+        ///     protected override void Dispose(bool disposing) {
+        ///         if (disposing)
+        ///             lock(m_sync) {
+        ///                 m_file.Dipose();
+        ///                 base.Dispose(true);
+        ///             }
+        ///         else
+        ///             base.Dispose(false);
+        ///     }
+        /// }
+        /// <example> 
         protected void AssertNotDisposed() {
-            if (m_disposed)
-                throw new ObjectDisposedException(this.ToString());
+            Thread.MemoryBarrier();
+            if (m_disposed != 0)
+                throw new ObjectDisposedException(ToString());
         }
         /// <summary>
-        /// Переводит объект в состояние <c>Disposed</c> и вызывает событие <see cref="Disposed"/>
+        /// Вызывает событие <see cref="Disposed"/>
         /// </summary>
         /// <param name="disposing">Признак того, что нужно освободить ресурсы, иначе данный метод
         /// вызван сборщиком мусора и нужно освобождать ТОЛЬКО неуправляемые ресурсы ТОЛЬКО этого
         /// объекта.</param>
         /// <remarks>
-        /// Данный метод осуществляет проверку того, что объект уже был освобожден, чтобы не вызывать
-        /// событие <see cref="Disposed"/>. Не поддерживает многопоточность.
+        /// Данный метод вызывается гарантированно один раз даже при одновременном вызове <see cref="Dispose()"/>
+        /// из нескольких потоков.
         /// </remarks>
         protected virtual void Dispose(bool disposing) {
-            if (disposing && !m_disposed) {
-                m_disposed = true;
-                
+            if (disposing) {
                 EventHandler temp = Disposed;
-                if (temp != null) 
-                    temp(this,EventArgs.Empty);
+                if (temp != null)
+                    temp(this, EventArgs.Empty);
             }
         }
+
         public void Dispose() {
-            Dispose(true);
-            GC.SuppressFinalize(this);
+            if (Interlocked.Increment(ref m_disposed) == 1) {
+                Dispose(true);
+                GC.SuppressFinalize(this);
+            }
         }
 
         /// <summary>