# HG changeset patch # User cin # Date 2016-02-10 22:56:27 # Node ID 240aa6994018bec83878f130daa91e23dece8b1a # Parent ec91a6dfa5b3f458072b9373a36c2e5ddb231c68 component model refactoring diff --git a/Implab/Component.cs b/Implab/Component.cs deleted file mode 100644 --- a/Implab/Component.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Web; - -namespace Implab { - /// - /// Компоненты являются состовными объектами, имеют детерминированный период жизни, автоматически освобождают ресурсы входящие в них. - /// - /// Компонента управляет временем жизни включенных в нее компонент - public class Component: Disposable { - LinkedList m_components = new LinkedList(); - - /// - /// Коллекция компонент, из которых состоит текущая компонента. - /// - public ICollection Components { - get { - AssertNotDisposed(); - return m_components; - } - } - - /// - /// Освобождает компоненты, входящие в состав текущей компоненты. - /// - /// Признак того, что происходит освобождение ресурсов. - protected override void Dispose(bool disposing) { - if (disposing) { - foreach (var item in m_components) - item.Dispose(); - m_components.Clear(); - } - base.Dispose(disposing); - } - } -} \ No newline at end of file diff --git a/Implab/ComponentContainer.cs b/Implab/ComponentContainer.cs deleted file mode 100644 --- a/Implab/ComponentContainer.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using Implab.Parallels; -using System.Threading; - -namespace Implab { - public class ComponentContainer : IComponentContainer, IDisposable { - static readonly ComponentContainer _appContainer; - - static ComponentContainer() { - _appContainer = new ComponentContainer(); - AppDomain.CurrentDomain.ProcessExit += HandleProcessExit; - } - - public static ComponentContainer Global { - get { - return _appContainer; - } - } - - bool m_disposed; - readonly AsyncQueue m_components = new AsyncQueue(); - - public void Add(IDisposable item) { - Safe.ArgumentNotNull(item, "item"); - Thread.MemoryBarrier(); - if (m_disposed) { - item.Dispose(); - } else { - m_components.Enqueue(item); - if (m_disposed && m_components.TryDequeue(out item)) - item.Dispose(); - } - } - - public void Dispose() { - m_disposed = true; - IDisposable item; - while (m_components.TryDequeue(out item)) - item.Dispose(); - } - - static void HandleProcessExit (object sender, EventArgs e) - { - _appContainer.Dispose(); - } - } -} - diff --git a/Implab/Components/App.cs b/Implab/Components/App.cs new file mode 100644 --- /dev/null +++ b/Implab/Components/App.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; + +namespace Implab.Components { + /// + /// Global application components and services. + /// + public static class App { + readonly static ComponentContainer _root = new ComponentContainer(); + + public static ICollection RootContainer { + get { return _root; } + } + + static App() { + AppDomain.CurrentDomain.ProcessExit += (sender, e) => _root.Dispose(); + } + } +} + diff --git a/Implab/Components/ComponentContainer.cs b/Implab/Components/ComponentContainer.cs new file mode 100644 --- /dev/null +++ b/Implab/Components/ComponentContainer.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Implab.Components { + /// + /// Component container. + /// + /// Instanses of this class are thread safe. + public class ComponentContainer : Disposable, ICollection { + readonly HashSet m_components = new HashSet(); + + public void Clear() { + T[] removed; + + lock (m_components) { + removed = new T[m_components.Count]; + m_components.CopyTo(removed); + m_components.Clear(); + } + + foreach (var item in removed.OfType()) + item.Dispose(); + } + + public bool Contains(T item) { + lock (m_components) + return m_components.Contains(item); + } + + public void CopyTo(T[] array, int arrayIndex) { + lock (m_components) + m_components.CopyTo(array, arrayIndex); + } + + public bool Remove(T item) { + lock (m_components) + return m_components.Remove(item); + } + + public int Count { + get { + lock (m_components) + return m_components.Count; + } + } + + public bool IsReadOnly { + get { + return false; + } + } + + public IEnumerator GetEnumerator() { + T[] items; + lock (m_components) { + items = new T[m_components.Count]; + m_components.CopyTo(items); + return (IEnumerator)items.GetEnumerator(); + } + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { + return GetEnumerator(); + } + + public void Add(T item) { + Safe.ArgumentNotNull(item, "item"); + + lock (m_components) { + if (IsDisposed) + Safe.Dispose(item); + else + m_components.Add(item); + } + } + + protected override void Dispose(bool disposing) { + base.Dispose(disposing); + Clear(); + } + } +} + diff --git a/Implab/Components/Disposable.cs b/Implab/Components/Disposable.cs new file mode 100644 --- /dev/null +++ b/Implab/Components/Disposable.cs @@ -0,0 +1,103 @@ +using Implab.Diagnostics; +using System; +using System.Threading; + +namespace Implab.Components { + /// + /// Base class the objects which support disposing. + /// + public class Disposable : IDisposable { + + int m_disposed; + + public event EventHandler Disposed; + + public bool IsDisposed { + get { + Thread.MemoryBarrier(); + return m_disposed != 0; + } + } + + /// + /// Asserts the object is not disposed. + /// + /// The object is disposed + /// + /// Успешная проверка того, что объект не освобожден еще не гарантирует, что он не + /// будет освобожден сразу после нее, поэтому методы использующие проверку должны + /// учитывать, что объект может быть освобожден из параллельного потока. + /// Данны метод служит для упрощения отладки ошибок при использовании объекта после его + /// освобождения. + /// + /// + /// // пример синхронизированного освобождения ресурсов + /// 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); + /// } + /// } + /// + protected void AssertNotDisposed() { + Thread.MemoryBarrier(); + if (m_disposed != 0) + throw new ObjectDisposedException(ToString()); + } + /// + /// Вызывает событие + /// + /// Признак того, что нужно освободить ресурсы, иначе данный метод + /// вызван сборщиком мусора и нужно освобождать ТОЛЬКО неуправляемые ресурсы ТОЛЬКО этого + /// объекта. + /// + /// Данный метод вызывается гарантированно один раз даже при одновременном вызове + /// из нескольких потоков. + /// + protected virtual void Dispose(bool disposing) { + if (disposing) { + EventHandler temp = Disposed; + if (temp != null) + temp(this, EventArgs.Empty); + } + } + + public void Dispose() { + if (Interlocked.Increment(ref m_disposed) == 1) { + Dispose(true); + GC.SuppressFinalize(this); + } + } + + /// + /// Записывает сообщение об утечке объекта. + /// + protected virtual void ReportObjectLeaks() { + TraceLog.TraceWarning("The object is marked as disposable but isn't disposed properly: {0}", this); + } + + ~Disposable() { + Dispose(false); + ReportObjectLeaks(); + } + } +} \ No newline at end of file diff --git a/Implab/Components/DisposablePool.cs b/Implab/Components/DisposablePool.cs new file mode 100644 --- /dev/null +++ b/Implab/Components/DisposablePool.cs @@ -0,0 +1,90 @@ +using System; +using Implab.Parallels; +using System.Threading; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; + +namespace Implab { + public abstract class DisposablePool : IDisposable { + readonly int m_size; + readonly AsyncQueue m_queue = new AsyncQueue(); + + [SuppressMessage("Microsoft.Design", "CA1000:DoNotDeclareStaticMembersOnGenericTypes")] + static readonly bool _isValueType = typeof(T).IsValueType; + + bool m_disposed; + + int m_count; + + protected DisposablePool(int size) { + m_size = size; + } + + protected DisposablePool() : this(Environment.ProcessorCount+1) { + } + + public T Allocate() { + if (m_disposed) + throw new ObjectDisposedException(ToString()); + + T instance; + if (m_queue.TryDequeue(out instance)) { + Interlocked.Decrement(ref m_count); + } else { + instance = CreateInstance(); + Debug.Assert(!Object.Equals(instance, default(T)) || _isValueType); + } + return instance; + } + + protected abstract T CreateInstance(); + + protected virtual void CleanupInstance(T instance) { + } + + public void Release(T instance) { + if ( Object.Equals(instance,default(T)) && !_isValueType) + return; + + Thread.MemoryBarrier(); + if (m_count < m_size && !m_disposed) { + Interlocked.Increment(ref m_count); + + CleanupInstance(instance); + + m_queue.Enqueue(instance); + + // пока элемент возвращался в кеш, была начата операция освобождения всего кеша + // и возможно уже законцена, в таком случае следует извлечь элемент обратно и + // освободить его. Если операция освобождения кеша еще не заврешилась, то будет + // изъят и освобожден произвольный элемен, что не повлияет на ход всего процесса. + if (m_disposed && m_queue.TryDequeue(out instance) && instance is IDisposable) + ((IDisposable)instance).Dispose() ; + + } else { + if (instance is IDisposable) + ((IDisposable)instance).Dispose(); + } + } + + protected virtual void Dispose(bool disposing) { + if (disposing) { + m_disposed = true; + T instance; + while (m_queue.TryDequeue(out instance)) + if (instance is IDisposable) + ((IDisposable)instance).Dispose(); + } + } + + #region IDisposable implementation + + public void Dispose() { + Dispose(true); + GC.SuppressFinalize(this); + } + + #endregion + } +} + diff --git a/Implab/Components/ExecutionState.cs b/Implab/Components/ExecutionState.cs new file mode 100644 --- /dev/null +++ b/Implab/Components/ExecutionState.cs @@ -0,0 +1,12 @@ +namespace Implab.Components { + public enum ExecutionState { + Uninitialized, + Initial, + Starting, + Running, + Stopping, + Stopped, + Disposed, + Failed + } +} \ No newline at end of file diff --git a/Implab/Components/IInitializable.cs b/Implab/Components/IInitializable.cs new file mode 100644 --- /dev/null +++ b/Implab/Components/IInitializable.cs @@ -0,0 +1,21 @@ +using System; + +namespace Implab.Components { + /// + /// Initializable components are created and initialized in two steps, first we have create the component, + /// then we have to complete it's creation by calling an method. All parameters needed + /// to complete the initialization must be passed before the calling + /// + public interface IInitializable { + /// + /// Completes initialization. + /// + /// + /// Normally virtual shouldn't be called from the constructor, due to the incomplete object state, but + /// they can be called from this method. This method is also usefull when we constructing a complex grpah + /// of components where cyclic references may take place. + /// + void Init(); + } +} + diff --git a/Implab/Components/IRunnable.cs b/Implab/Components/IRunnable.cs new file mode 100644 --- /dev/null +++ b/Implab/Components/IRunnable.cs @@ -0,0 +1,14 @@ +using System; + +namespace Implab.Components { + public interface IRunnable { + IPromise Start(); + + IPromise Stop(); + + ExecutionState State { get; } + + Exception LastError { get; } + } +} + diff --git a/Implab/Components/ObjectPool.cs b/Implab/Components/ObjectPool.cs new file mode 100644 --- /dev/null +++ b/Implab/Components/ObjectPool.cs @@ -0,0 +1,60 @@ +using Implab.Parallels; +using System; +using System.Threading; + +namespace Implab.Components { + /// + /// Базовый класс для создания пулов объектов. + /// + /// + /// Пул объектов позволяет многократно использовать один и тотже объект, + /// что актуально для объектов, создание которых требует существенных ресурсов. + /// Пул объектов использует слабые ссылки, чтобы не препятствовать освобождению + /// ресурсов и создает новые объекты при необходимости. + /// + /// Наследники должны реализовывать метод для создания + /// новых экземпляров. + /// + /// Пул поддерживает обращения сразу из нескольких потоков. + /// + public abstract class ObjectPool where T : class { + readonly AsyncQueue m_queue = new AsyncQueue(); + readonly int m_size; + int m_count = 0; + + protected ObjectPool() : this(Environment.ProcessorCount+1) { + + } + + protected ObjectPool(int size) { + Safe.ArgumentInRange(size,1,size,"size"); + + m_size = size; + } + + protected abstract T CreateInstance(); + + protected virtual void CleanupInstance(T instance) { + } + + public T Allocate() { + WeakReference reference; + while (m_queue.TryDequeue(out reference)) { + Interlocked.Decrement(ref m_count); + object instance = reference.Target; + if (instance == null) + continue; + return (T)instance; + } + return CreateInstance(); + } + + public void Release(T instance) { + if (m_count < m_size && instance != null) { + Interlocked.Increment(ref m_count); + CleanupInstance(instance); + m_queue.Enqueue(new WeakReference(instance)); + } + } + } +} diff --git a/Implab/Components/ServiceLocator.cs b/Implab/Components/ServiceLocator.cs new file mode 100644 --- /dev/null +++ b/Implab/Components/ServiceLocator.cs @@ -0,0 +1,248 @@ +using System; +using System.Collections.Generic; + +namespace Implab.Components { + /// + /// Коллекция сервисов, позволяет регистрировать и получать сервисы. + /// + public class ServiceLocator: Disposable, IServiceLocator, IServiceProvider { + // запись о сервисе + struct ServiceEntry : IDisposable { + public object service; // сервис + public bool shared; // признак того, что сервис НЕ нужно освобождать + public Func activator; // активатор сервиса при первом обращении + public Action cleanup; // функция для очистки сервиса + public List associated; // ссылки на текущую запись + public Type origin; // ссылка на оригинальную запись о сервисе + + #region IDisposable implementation + + public void Dispose() { + if (shared) + return; + if (cleanup != null) { + if (service != null) + cleanup(service); + } else + Safe.Dispose(service); + } + + #endregion + } + + // словарь существующих сервисов + readonly Dictionary m_services = new Dictionary(); + + /// + /// Получает объект предоставляющий сервис . + /// + /// Тип запрашиваемого сервиса + /// Объект, реализующий сервис + /// Сервис не зарегистрирован + public T GetService() { + object result; + if (TryGetService(typeof(T), out result)) + return (T)result; + throw new ApplicationException (String.Format ("{0} doesn't provide {1} service", this, typeof(T))); + } + + + /// + /// Пытается получить указанный сервис, в случае, если компонента не предоставляет требуемый сервис + /// не возникает исключений. + /// + /// Тип требуемого сервиса. + /// Объект реализующий сервис, или default(T) если такового нет. + /// true - сервис найден, false - сервис не зарегистрирован. + public bool TryGetService(out T service) { + object result; + if (TryGetService(typeof(T), out result)) { + service = (T)result; + return true; + } + service = default(T); + return false; + } + + /// + /// Получает объект предоставляющий сервис + /// + /// Тип запрашиваемого сервиса + /// Объект, реализующий сервис + /// Сервис не зарегистрирован + public object GetService(Type serviceType) { + object result; + if (TryGetService(serviceType, out result)) + return result; + throw new ApplicationException (String.Format ("{0} doesn't provide {1} service", this, serviceType)); + } + + /// + /// Пытается получить требуемый сервис или совместимый с ним. + /// + /// true, если сервис был найден, false в противном случае.. + /// Тип запрашиваемого сервиса. + /// Искомый сервис. + public virtual bool TryGetService(Type serviceType, out object service) { + Safe.ArgumentNotNull(serviceType, "serviceType"); + AssertNotDisposed(); + + ServiceEntry se; + if (!m_services.TryGetValue(serviceType, out se)) { + // ищем ближайщий объект, реализующий нужный сервис + Type pt = null; + foreach (var t in m_services.Keys) + if (serviceType.IsAssignableFrom(t) && (pt == null || t.IsAssignableFrom(pt))) + pt = t; + + if (pt == null) { + // нет нужного сервиса + service = null; + return false; + } + + var pe = m_services[pt]; + + // найденная запись может ссылаться на оригинальную запись с сервисом + if(pe.origin != null) { + pt = pe.origin; + pe = m_services[pt]; + } + + // добавляем список с обратными ссылками + if (pe.associated == null) + pe.associated = new List(); + + pe.associated.Add(serviceType); + + // обновляем родительскую запись + m_services[pt] = pe; + + // создаем запись со ссылкой + se = new ServiceEntry { + service = pe.service, + origin = pt, + shared = true // предотвращаем множественные попытки освобождения + }; + + m_services[serviceType] = se; + } + + // запись содержит в себе информацию о сервисе + if (se.service != null) { + service = se.service; + return true; + } + + // текущая запись является ссылкой + if (se.origin != null) { + se.service = GetService(se.origin); + m_services[serviceType] = se; + service = se.service; + return true; + } + + // текущая запись не является ссылкой и не имеет информации о сервисе + // она должна сожержать информацию об активации + if (se.activator != null) { + se.service = se.activator(); + + m_services[serviceType] = se; + + service = se.service; + return true; + } + + service = null; + return false; + } + + /// + /// Регистрирует фабрику для активации сервиса по первому требованию. + /// + /// Тип регистрируемого сервиса. + /// Фабрика для создания/получения объекта, предоставляющего сервис. + /// Метод для освобождения экземпляра сервиса, будет вызыван при освобождении сервис-локатора. + /// При освобождении сервис-локатора, сервисы полученные в результате активации также будут освобождены. + public void Register(Func activator, Action cleanup) { + Safe.ArgumentNotNull(activator, "activator"); + + AssertNotDisposed(); + + Unregister(typeof(T)); + + var serviceEntry = new ServiceEntry(); + serviceEntry.activator = () => activator(); + if (cleanup != null) + serviceEntry.cleanup = instance => cleanup((T)instance); + m_services[typeof(T)] = serviceEntry; + } + + public void Register(Func activator) { + Register(activator, null); + } + + /// + /// Регистрирует объект, предоставляющий сервис. + /// + /// Тип регистрируемого сервиса. + /// Объект, предоставляющий сервис. + /// Указанный сервис уже зарегистрирован. + /// Сервис-локатором не управляет временем жизни объекта для зарегистрированного сервиса. + public void Register(T service) { + Register(service, true); + } + + /// + /// Регистрирует объект, предоставляющий сервис. Повторная регистрация отменяет уже существующую. + /// + /// Тип регистрируемого сервиса. + /// Объект, предоставляющий сервис. + /// Признак того, что объект является разделяемым и сервис-локатор не должен его освобождать. + public void Register(T service, bool shared) { + Safe.ArgumentNotNull(service, "service"); + + AssertNotDisposed(); + + Unregister(typeof(T)); + + m_services[typeof(T)] = new ServiceEntry { service = service, shared = shared }; + } + + public void Unregister(Type serviceType) { + Safe.ArgumentNotNull(serviceType, "serviceType"); + + AssertNotDisposed(); + + ServiceEntry se; + if (m_services.TryGetValue(serviceType, out se)) { + if (se.origin != null) { + var pe = m_services[se.origin]; + pe.associated.Remove(serviceType); + } + // освобождаем ресурсы + se.Dispose(); + m_services.Remove(serviceType); + + // убираем связанные записи + if (se.associated != null) + foreach (var item in se.associated) + m_services.Remove(item); + } + } + + /// + /// Освобождает зарегистрированные сервисы (которые требуется освобоить). + /// + /// Призанак того, что нужно освободить ресурсы. + protected override void Dispose(bool disposing) { + if (disposing) { + + foreach (var entry in m_services.Values) + entry.Dispose(); + + } + base.Dispose(disposing); + } + } +} \ No newline at end of file diff --git a/Implab/Diagnostics/ListenerBase.cs b/Implab/Diagnostics/ListenerBase.cs --- a/Implab/Diagnostics/ListenerBase.cs +++ b/Implab/Diagnostics/ListenerBase.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; +using Implab.Components; namespace Implab.Diagnostics { public abstract class ListenerBase : ServiceLocator, ILogWriter, ILogWriter { diff --git a/Implab/Disposable.cs b/Implab/Disposable.cs deleted file mode 100644 --- a/Implab/Disposable.cs +++ /dev/null @@ -1,104 +0,0 @@ -using Implab.Diagnostics; -using System; -using System.Threading; -using System.IO; - -namespace Implab { - /// - /// Объект, поддерживающий освобождение ресурсов. - /// - public class Disposable : IDisposable { - - int m_disposed; - - public event EventHandler Disposed; - - public bool IsDisposed { - get { - Thread.MemoryBarrier(); - return m_disposed != 0; - } - } - - /// - /// Asserts the object is not disposed. - /// - /// The object is disposed - /// - /// Успешная проверка того, что объект не освобожден еще не гарантирует, что он не - /// будет освобожден сразу после нее, поэтому методы использующие проверку должны - /// учитывать, что объект может быть освобожден из параллельного потока. - /// Данны метод служит для упрощения отладки ошибок при использовании объекта после его - /// освобождения. - /// - /// - /// // пример синхронизированного освобождения ресурсов - /// 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); - /// } - /// } - /// - protected void AssertNotDisposed() { - Thread.MemoryBarrier(); - if (m_disposed != 0) - throw new ObjectDisposedException(ToString()); - } - /// - /// Вызывает событие - /// - /// Признак того, что нужно освободить ресурсы, иначе данный метод - /// вызван сборщиком мусора и нужно освобождать ТОЛЬКО неуправляемые ресурсы ТОЛЬКО этого - /// объекта. - /// - /// Данный метод вызывается гарантированно один раз даже при одновременном вызове - /// из нескольких потоков. - /// - protected virtual void Dispose(bool disposing) { - if (disposing) { - EventHandler temp = Disposed; - if (temp != null) - temp(this, EventArgs.Empty); - } - } - - public void Dispose() { - if (Interlocked.Increment(ref m_disposed) == 1) { - Dispose(true); - GC.SuppressFinalize(this); - } - } - - /// - /// Записывает сообщение об утечке объекта. - /// - protected virtual void ReportObjectLeaks() { - TraceLog.TraceWarning("The object is marked as disposable but isn't disposed properly: {0}", this); - } - - ~Disposable() { - Dispose(false); - ReportObjectLeaks(); - } - } -} \ No newline at end of file diff --git a/Implab/DisposablePool.cs b/Implab/DisposablePool.cs deleted file mode 100644 --- a/Implab/DisposablePool.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System; -using Implab.Parallels; -using System.Threading; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; - -namespace Implab { - public abstract class DisposablePool : IDisposable { - readonly int m_size; - readonly AsyncQueue m_queue = new AsyncQueue(); - - [SuppressMessage("Microsoft.Design", "CA1000:DoNotDeclareStaticMembersOnGenericTypes")] - static readonly bool _isValueType = typeof(T).IsValueType; - - bool m_disposed; - - int m_count; - - protected DisposablePool(int size) { - m_size = size; - } - - protected DisposablePool() : this(Environment.ProcessorCount+1) { - } - - public T Allocate() { - if (m_disposed) - throw new ObjectDisposedException(ToString()); - - T instance; - if (m_queue.TryDequeue(out instance)) { - Interlocked.Decrement(ref m_count); - } else { - instance = CreateInstance(); - Debug.Assert(!Object.Equals(instance, default(T)) || _isValueType); - } - return instance; - } - - protected abstract T CreateInstance(); - - protected virtual void CleanupInstance(T instance) { - } - - public void Release(T instance) { - if ( Object.Equals(instance,default(T)) && !_isValueType) - return; - - Thread.MemoryBarrier(); - if (m_count < m_size && !m_disposed) { - Interlocked.Increment(ref m_count); - - CleanupInstance(instance); - - m_queue.Enqueue(instance); - - // пока элемент возвращался в кеш, была начата операция освобождения всего кеша - // и возможно уже законцена, в таком случае следует извлечь элемент обратно и - // освободить его. Если операция освобождения кеша еще не заврешилась, то будет - // изъят и освобожден произвольный элемен, что не повлияет на ход всего процесса. - if (m_disposed && m_queue.TryDequeue(out instance) && instance is IDisposable) - ((IDisposable)instance).Dispose() ; - - } else { - if (instance is IDisposable) - ((IDisposable)instance).Dispose(); - } - } - - protected virtual void Dispose(bool disposing) { - if (disposing) { - m_disposed = true; - T instance; - while (m_queue.TryDequeue(out instance)) - if (instance is IDisposable) - ((IDisposable)instance).Dispose(); - } - } - - #region IDisposable implementation - - public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); - } - - #endregion - } -} - diff --git a/Implab/IComponentContainer.cs b/Implab/IComponentContainer.cs deleted file mode 100644 --- a/Implab/IComponentContainer.cs +++ /dev/null @@ -1,8 +0,0 @@ -using System; - -namespace Implab { - public interface IComponentContainer { - void Add(IDisposable component); - } -} - diff --git a/Implab/Implab.csproj b/Implab/Implab.csproj --- a/Implab/Implab.csproj +++ b/Implab/Implab.csproj @@ -75,7 +75,6 @@ - @@ -85,7 +84,6 @@ - @@ -130,8 +128,6 @@ - - @@ -144,11 +140,7 @@ - - - - @@ -180,6 +172,16 @@ + + + + + + + + + + @@ -252,4 +254,7 @@ + + + \ No newline at end of file diff --git a/Implab/ObjectPool.cs b/Implab/ObjectPool.cs deleted file mode 100644 --- a/Implab/ObjectPool.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Implab.Parallels; -using System; -using System.Threading; - -namespace Implab { - /// - /// Базовый класс для создания пулов объектов. - /// - /// - /// Пул объектов позволяет многократно использовать один и тотже объект, - /// что актуально для объектов, создание которых требует существенных ресурсов. - /// Пул объектов использует слабые ссылки, чтобы не препятствовать освобождению - /// ресурсов и создает новые объекты при необходимости. - /// - /// Наследники должны реализовывать метод для создания - /// новых экземпляров. - /// - /// Пул поддерживает обращения сразу из нескольких потоков. - /// - public abstract class ObjectPool where T : class { - readonly AsyncQueue m_queue = new AsyncQueue(); - readonly int m_size; - int m_count = 0; - - protected ObjectPool() : this(Environment.ProcessorCount+1) { - - } - - protected ObjectPool(int size) { - Safe.ArgumentInRange(size,1,size,"size"); - - m_size = size; - } - - protected abstract T CreateInstance(); - - protected virtual void CleanupInstance(T instance) { - } - - public T Allocate() { - WeakReference reference; - while (m_queue.TryDequeue(out reference)) { - Interlocked.Decrement(ref m_count); - object instance = reference.Target; - if (instance == null) - continue; - return (T)instance; - } - return CreateInstance(); - } - - public void Release(T instance) { - if (m_count < m_size && instance != null) { - Interlocked.Increment(ref m_count); - CleanupInstance(instance); - m_queue.Enqueue(new WeakReference(instance)); - } - } - } -} diff --git a/Implab/Parsing/Scanner.cs b/Implab/Parsing/Scanner.cs --- a/Implab/Parsing/Scanner.cs +++ b/Implab/Parsing/Scanner.cs @@ -2,9 +2,7 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using Implab.Components; namespace Implab.Parsing { /// diff --git a/Implab/ServiceLocator.cs b/Implab/ServiceLocator.cs deleted file mode 100644 --- a/Implab/ServiceLocator.cs +++ /dev/null @@ -1,248 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Implab { - /// - /// Коллекция сервисов, позволяет регистрировать и получать сервисы. - /// - public class ServiceLocator: Disposable, IServiceLocator, IServiceProvider { - // запись о сервисе - struct ServiceEntry : IDisposable { - public object service; // сервис - public bool shared; // признак того, что сервис НЕ нужно освобождать - public Func activator; // активатор сервиса при первом обращении - public Action cleanup; // функция для очистки сервиса - public List associated; // ссылки на текущую запись - public Type origin; // ссылка на оригинальную запись о сервисе - - #region IDisposable implementation - - public void Dispose() { - if (shared) - return; - if (cleanup != null) { - if (service != null) - cleanup(service); - } else - Safe.Dispose(service); - } - - #endregion - } - - // словарь существующих сервисов - readonly Dictionary m_services = new Dictionary(); - - /// - /// Получает объект предоставляющий сервис . - /// - /// Тип запрашиваемого сервиса - /// Объект, реализующий сервис - /// Сервис не зарегистрирован - public T GetService() { - object result; - if (TryGetService(typeof(T), out result)) - return (T)result; - throw new ApplicationException (String.Format ("{0} doesn't provide {1} service", this, typeof(T))); - } - - - /// - /// Пытается получить указанный сервис, в случае, если компонента не предоставляет требуемый сервис - /// не возникает исключений. - /// - /// Тип требуемого сервиса. - /// Объект реализующий сервис, или default(T) если такового нет. - /// true - сервис найден, false - сервис не зарегистрирован. - public bool TryGetService(out T service) { - object result; - if (TryGetService(typeof(T), out result)) { - service = (T)result; - return true; - } - service = default(T); - return false; - } - - /// - /// Получает объект предоставляющий сервис - /// - /// Тип запрашиваемого сервиса - /// Объект, реализующий сервис - /// Сервис не зарегистрирован - public object GetService(Type serviceType) { - object result; - if (TryGetService(serviceType, out result)) - return result; - throw new ApplicationException (String.Format ("{0} doesn't provide {1} service", this, serviceType)); - } - - /// - /// Пытается получить требуемый сервис или совместимый с ним. - /// - /// true, если сервис был найден, false в противном случае.. - /// Тип запрашиваемого сервиса. - /// Искомый сервис. - public virtual bool TryGetService(Type serviceType, out object service) { - Safe.ArgumentNotNull(serviceType, "serviceType"); - AssertNotDisposed(); - - ServiceEntry se; - if (!m_services.TryGetValue(serviceType, out se)) { - // ищем ближайщий объект, реализующий нужный сервис - Type pt = null; - foreach (var t in m_services.Keys) - if (serviceType.IsAssignableFrom(t) && (pt == null || t.IsAssignableFrom(pt))) - pt = t; - - if (pt == null) { - // нет нужного сервиса - service = null; - return false; - } - - var pe = m_services[pt]; - - // найденная запись может ссылаться на оригинальную запись с сервисом - if(pe.origin != null) { - pt = pe.origin; - pe = m_services[pt]; - } - - // добавляем список с обратными ссылками - if (pe.associated == null) - pe.associated = new List(); - - pe.associated.Add(serviceType); - - // обновляем родительскую запись - m_services[pt] = pe; - - // создаем запись со ссылкой - se = new ServiceEntry { - service = pe.service, - origin = pt, - shared = true // предотвращаем множественные попытки освобождения - }; - - m_services[serviceType] = se; - } - - // запись содержит в себе информацию о сервисе - if (se.service != null) { - service = se.service; - return true; - } - - // текущая запись является ссылкой - if (se.origin != null) { - se.service = GetService(se.origin); - m_services[serviceType] = se; - service = se.service; - return true; - } - - // текущая запись не является ссылкой и не имеет информации о сервисе - // она должна сожержать информацию об активации - if (se.activator != null) { - se.service = se.activator(); - - m_services[serviceType] = se; - - service = se.service; - return true; - } - - service = null; - return false; - } - - /// - /// Регистрирует фабрику для активации сервиса по первому требованию. - /// - /// Тип регистрируемого сервиса. - /// Фабрика для создания/получения объекта, предоставляющего сервис. - /// Метод для освобождения экземпляра сервиса, будет вызыван при освобождении сервис-локатора. - /// При освобождении сервис-локатора, сервисы полученные в результате активации также будут освобождены. - public void Register(Func activator, Action cleanup) { - Safe.ArgumentNotNull(activator, "activator"); - - AssertNotDisposed(); - - Unregister(typeof(T)); - - var serviceEntry = new ServiceEntry(); - serviceEntry.activator = () => activator(); - if (cleanup != null) - serviceEntry.cleanup = instance => cleanup((T)instance); - m_services[typeof(T)] = serviceEntry; - } - - public void Register(Func activator) { - Register(activator, null); - } - - /// - /// Регистрирует объект, предоставляющий сервис. - /// - /// Тип регистрируемого сервиса. - /// Объект, предоставляющий сервис. - /// Указанный сервис уже зарегистрирован. - /// Сервис-локатором не управляет временем жизни объекта для зарегистрированного сервиса. - public void Register(T service) { - Register(service, true); - } - - /// - /// Регистрирует объект, предоставляющий сервис. Повторная регистрация отменяет уже существующую. - /// - /// Тип регистрируемого сервиса. - /// Объект, предоставляющий сервис. - /// Признак того, что объект является разделяемым и сервис-локатор не должен его освобождать. - public void Register(T service, bool shared) { - Safe.ArgumentNotNull(service, "service"); - - AssertNotDisposed(); - - Unregister(typeof(T)); - - m_services[typeof(T)] = new ServiceEntry { service = service, shared = shared }; - } - - public void Unregister(Type serviceType) { - Safe.ArgumentNotNull(serviceType, "serviceType"); - - AssertNotDisposed(); - - ServiceEntry se; - if (m_services.TryGetValue(serviceType, out se)) { - if (se.origin != null) { - var pe = m_services[se.origin]; - pe.associated.Remove(serviceType); - } - // освобождаем ресурсы - se.Dispose(); - m_services.Remove(serviceType); - - // убираем связанные записи - if (se.associated != null) - foreach (var item in se.associated) - m_services.Remove(item); - } - } - - /// - /// Освобождает зарегистрированные сервисы (которые требуется освобоить). - /// - /// Призанак того, что нужно освободить ресурсы. - protected override void Dispose(bool disposing) { - if (disposing) { - - foreach (var entry in m_services.Values) - entry.Dispose(); - - } - base.Dispose(disposing); - } - } -} \ No newline at end of file