@@ -0,0 +1,90 | |||
|
1 | using System; | |
|
2 | using Implab.Parallels; | |
|
3 | using System.Threading; | |
|
4 | using System.Diagnostics; | |
|
5 | using System.Diagnostics.CodeAnalysis; | |
|
6 | ||
|
7 | namespace Implab { | |
|
8 | public abstract class DisposablePool<T> : IDisposable { | |
|
9 | readonly int m_size; | |
|
10 | readonly MTQueue<T> m_queue = new MTQueue<T>(); | |
|
11 | ||
|
12 | [SuppressMessage("Microsoft.Design", "CA1000:DoNotDeclareStaticMembersOnGenericTypes")] | |
|
13 | static readonly bool _isValueType = typeof(T).IsValueType; | |
|
14 | ||
|
15 | bool m_disposed; | |
|
16 | ||
|
17 | int m_count; | |
|
18 | ||
|
19 | protected DisposablePool(int size) { | |
|
20 | m_size = size; | |
|
21 | } | |
|
22 | ||
|
23 | protected DisposablePool() : this(Environment.ProcessorCount+1) { | |
|
24 | } | |
|
25 | ||
|
26 | public T Allocate() { | |
|
27 | if (m_disposed) | |
|
28 | throw new ObjectDisposedException(ToString()); | |
|
29 | ||
|
30 | T instance; | |
|
31 | if (m_queue.TryDequeue(out instance)) { | |
|
32 | Interlocked.Decrement(ref m_count); | |
|
33 | } else { | |
|
34 | instance = CreateInstance(); | |
|
35 | Debug.Assert(!Object.Equals(instance, default(T)) || _isValueType); | |
|
36 | } | |
|
37 | return instance; | |
|
38 | } | |
|
39 | ||
|
40 | protected abstract T CreateInstance(); | |
|
41 | ||
|
42 | protected virtual void CleanupInstance(T instance) { | |
|
43 | } | |
|
44 | ||
|
45 | public void Release(T instance) { | |
|
46 | if ( Object.Equals(instance,default(T)) && !_isValueType) | |
|
47 | return; | |
|
48 | ||
|
49 | Thread.MemoryBarrier(); | |
|
50 | if (m_count < m_size && !m_disposed) { | |
|
51 | Interlocked.Increment(ref m_count); | |
|
52 | ||
|
53 | CleanupInstance(instance); | |
|
54 | ||
|
55 | m_queue.Enqueue(instance); | |
|
56 | ||
|
57 | // пока элемент возвращался в кеш, была начата операция освобождения всего кеша | |
|
58 | // и возможно уже законцена, в таком случае следует извлечь элемент обратно и | |
|
59 | // освободить его. Если операция освобождения кеша еще не заврешилась, то будет | |
|
60 | // изъят и освобожден произвольный элемен, что не повлияет на ход всего процесса. | |
|
61 | if (m_disposed && m_queue.TryDequeue(out instance) && instance is IDisposable) | |
|
62 | ((IDisposable)instance).Dispose() ; | |
|
63 | ||
|
64 | } else { | |
|
65 | if (instance is IDisposable) | |
|
66 | ((IDisposable)instance).Dispose(); | |
|
67 | } | |
|
68 | } | |
|
69 | ||
|
70 | protected virtual void Dispose(bool disposing) { | |
|
71 | if (disposing) { | |
|
72 | m_disposed = true; | |
|
73 | T instance; | |
|
74 | while (m_queue.TryDequeue(out instance)) | |
|
75 | if (instance is IDisposable) | |
|
76 | ((IDisposable)instance).Dispose(); | |
|
77 | } | |
|
78 | } | |
|
79 | ||
|
80 | #region IDisposable implementation | |
|
81 | ||
|
82 | public void Dispose() { | |
|
83 | Dispose(true); | |
|
84 | GC.SuppressFinalize(this); | |
|
85 | } | |
|
86 | ||
|
87 | #endregion | |
|
88 | } | |
|
89 | } | |
|
90 |
@@ -127,7 +127,6 | |||
|
127 | 127 | <Compile Include="Parsing\StarToken.cs" /> |
|
128 | 128 | <Compile Include="Parsing\SymbolToken.cs" /> |
|
129 | 129 | <Compile Include="Parsing\Token.cs" /> |
|
130 | <Compile Include="SafePool.cs" /> | |
|
131 | 130 | <Compile Include="ServiceLocator.cs" /> |
|
132 | 131 | <Compile Include="TaskController.cs" /> |
|
133 | 132 | <Compile Include="ProgressInitEventArgs.cs" /> |
@@ -139,7 +138,6 | |||
|
139 | 138 | <Compile Include="PromiseExtensions.cs" /> |
|
140 | 139 | <Compile Include="TransientPromiseException.cs" /> |
|
141 | 140 | <Compile Include="SyncContextPromise.cs" /> |
|
142 | <Compile Include="ObjectPool.cs" /> | |
|
143 | 141 | <Compile Include="Diagnostics\OperationContext.cs" /> |
|
144 | 142 | <Compile Include="Diagnostics\TraceContext.cs" /> |
|
145 | 143 | <Compile Include="Diagnostics\LogEventArgs.cs" /> |
@@ -150,6 +148,8 | |||
|
150 | 148 | <Compile Include="Parallels\MTCustomQueue.cs" /> |
|
151 | 149 | <Compile Include="Parallels\MTCustomQueueNode.cs" /> |
|
152 | 150 | <Compile Include="ComponentContainer.cs" /> |
|
151 | <Compile Include="DisposablePool.cs" /> | |
|
152 | <Compile Include="ObjectPool.cs" /> | |
|
153 | 153 | </ItemGroup> |
|
154 | 154 | <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> |
|
155 | 155 | <ItemGroup /> |
@@ -1,40 +1,35 | |||
|
1 | using System; | |
|
2 | using Implab.Parallels; | |
|
1 | using Implab.Parallels; | |
|
2 | using System; | |
|
3 | 3 | using System.Threading; |
|
4 | using System.Diagnostics; | |
|
5 | using System.Diagnostics.CodeAnalysis; | |
|
6 | 4 | |
|
7 | 5 | namespace Implab { |
|
8 | public abstract class ObjectPool<T> : IDisposable { | |
|
6 | /// <summary> | |
|
7 | /// Базовый класс для создания пулов объектов. | |
|
8 | /// </summary> | |
|
9 | /// <remarks> | |
|
10 | /// <para>Пул объектов позволяет многократно использовать один и тотже объект, | |
|
11 | /// что актуально для объектов, создание которых требует существенных ресурсов. | |
|
12 | /// Пул объектов использует слабые ссылки, чтобы не препятствовать освобождению | |
|
13 | /// ресурсов и создает новые объекты при необходимости.</para> | |
|
14 | /// <para> | |
|
15 | /// Наследники должны реализовывать метод <see cref="CreateInstance()"/> для создания | |
|
16 | /// новых экземпляров. | |
|
17 | /// </para> | |
|
18 | /// <para>Пул поддерживает обращения сразу из нескольких потоков.</para> | |
|
19 | /// </remarks> | |
|
20 | public abstract class ObjectPool<T> where T : class { | |
|
21 | readonly MTQueue<WeakReference> m_queue = new MTQueue<WeakReference>(); | |
|
9 | 22 | readonly int m_size; |
|
10 | readonly MTQueue<T> m_queue = new MTQueue<T>(); | |
|
23 | int m_count = 0; | |
|
11 | 24 | |
|
12 | [SuppressMessage("Microsoft.Design", "CA1000:DoNotDeclareStaticMembersOnGenericTypes")] | |
|
13 | static readonly bool _isValueType = typeof(T).IsValueType; | |
|
25 | protected ObjectPool() : this(Environment.ProcessorCount+1) { | |
|
14 | 26 | |
|
15 | bool m_disposed; | |
|
16 | ||
|
17 | int m_count; | |
|
27 | } | |
|
18 | 28 | |
|
19 | 29 | protected ObjectPool(int size) { |
|
20 | m_size = size; | |
|
21 | } | |
|
22 | ||
|
23 | protected ObjectPool() : this(Environment.ProcessorCount+1) { | |
|
24 | } | |
|
30 | Safe.ArgumentInRange(size,1,size,"size"); | |
|
25 | 31 | |
|
26 | public T Allocate() { | |
|
27 | if (m_disposed) | |
|
28 | throw new ObjectDisposedException(ToString()); | |
|
29 | ||
|
30 | T instance; | |
|
31 | if (m_queue.TryDequeue(out instance)) { | |
|
32 | Interlocked.Decrement(ref m_count); | |
|
33 | } else { | |
|
34 | instance = CreateInstance(); | |
|
35 | Debug.Assert(!Object.Equals(instance, default(T)) || _isValueType); | |
|
36 | } | |
|
37 | return instance; | |
|
32 | m_size = size; | |
|
38 | 33 | } |
|
39 | 34 | |
|
40 | 35 | protected abstract T CreateInstance(); |
@@ -42,49 +37,24 namespace Implab { | |||
|
42 | 37 | protected virtual void CleanupInstance(T instance) { |
|
43 | 38 | } |
|
44 | 39 | |
|
45 |
public |
|
|
46 | if ( Object.Equals(instance,default(T)) && !_isValueType) | |
|
47 | return; | |
|
48 | ||
|
49 | Thread.MemoryBarrier(); | |
|
50 | if (m_count < m_size && !m_disposed) { | |
|
51 | Interlocked.Increment(ref m_count); | |
|
52 | ||
|
53 | CleanupInstance(instance); | |
|
40 | public T Allocate() { | |
|
41 | WeakReference reference; | |
|
42 | while (m_queue.TryDequeue(out reference)) { | |
|
43 | Interlocked.Decrement(ref m_count); | |
|
44 | object instance = reference.Target; | |
|
45 | if (instance == null) | |
|
46 | continue; | |
|
47 | return (T)instance; | |
|
48 | } | |
|
49 | return CreateInstance(); | |
|
50 | } | |
|
54 | 51 | |
|
55 | m_queue.Enqueue(instance); | |
|
56 | ||
|
57 | // пока элемент возвращался в кеш, была начата операция освобождения всего кеша | |
|
58 | // и возможно уже законцена, в таком случае следует извлечь элемент обратно и | |
|
59 | // освободить его. Если операция освобождения кеша еще не заврешилась, то будет | |
|
60 | // изъят и освобожден произвольный элемен, что не повлияет на ход всего процесса. | |
|
61 | if (m_disposed && m_queue.TryDequeue(out instance) && instance is IDisposable) | |
|
62 | ((IDisposable)instance).Dispose() ; | |
|
63 | ||
|
64 | } else { | |
|
65 | if (instance is IDisposable) | |
|
66 | ((IDisposable)instance).Dispose(); | |
|
52 | public void Release(T instance) { | |
|
53 | if (m_count < m_size && instance != null) { | |
|
54 | Interlocked.Increment(ref m_count); | |
|
55 | CleanupInstance(instance); | |
|
56 | m_queue.Enqueue(new WeakReference(instance)); | |
|
67 | 57 | } |
|
68 | 58 | } |
|
69 | ||
|
70 | protected virtual void Dispose(bool disposing) { | |
|
71 | if (disposing) { | |
|
72 | m_disposed = true; | |
|
73 | T instance; | |
|
74 | while (m_queue.TryDequeue(out instance)) | |
|
75 | if (instance is IDisposable) | |
|
76 | ((IDisposable)instance).Dispose(); | |
|
77 | 59 | } |
|
78 | 60 | } |
|
79 | ||
|
80 | #region IDisposable implementation | |
|
81 | ||
|
82 | public void Dispose() { | |
|
83 | Dispose(true); | |
|
84 | GC.SuppressFinalize(this); | |
|
85 | } | |
|
86 | ||
|
87 | #endregion | |
|
88 | } | |
|
89 | } | |
|
90 |
@@ -5,7 +5,7 namespace Implab { | |||
|
5 | 5 | /// <summary> |
|
6 | 6 | /// Коллекция сервисов, позволяет регистрировать и получать сервисы. |
|
7 | 7 | /// </summary> |
|
8 |
public class ServiceLocator: |
|
|
8 | public class ServiceLocator: Disposable, IServiceLocator, IServiceProvider { | |
|
9 | 9 | // запись о сервисе |
|
10 | 10 | struct ServiceEntry : IDisposable { |
|
11 | 11 | public object service; // сервис |
|
1 | NO CONTENT: file was removed |
General Comments 0
You need to be logged in to leave comments.
Login now