@@ -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 | <Compile Include="Parsing\StarToken.cs" /> |
|
127 | <Compile Include="Parsing\StarToken.cs" /> | |
128 | <Compile Include="Parsing\SymbolToken.cs" /> |
|
128 | <Compile Include="Parsing\SymbolToken.cs" /> | |
129 | <Compile Include="Parsing\Token.cs" /> |
|
129 | <Compile Include="Parsing\Token.cs" /> | |
130 | <Compile Include="SafePool.cs" /> |
|
|||
131 | <Compile Include="ServiceLocator.cs" /> |
|
130 | <Compile Include="ServiceLocator.cs" /> | |
132 | <Compile Include="TaskController.cs" /> |
|
131 | <Compile Include="TaskController.cs" /> | |
133 | <Compile Include="ProgressInitEventArgs.cs" /> |
|
132 | <Compile Include="ProgressInitEventArgs.cs" /> | |
@@ -139,7 +138,6 | |||||
139 | <Compile Include="PromiseExtensions.cs" /> |
|
138 | <Compile Include="PromiseExtensions.cs" /> | |
140 | <Compile Include="TransientPromiseException.cs" /> |
|
139 | <Compile Include="TransientPromiseException.cs" /> | |
141 | <Compile Include="SyncContextPromise.cs" /> |
|
140 | <Compile Include="SyncContextPromise.cs" /> | |
142 | <Compile Include="ObjectPool.cs" /> |
|
|||
143 | <Compile Include="Diagnostics\OperationContext.cs" /> |
|
141 | <Compile Include="Diagnostics\OperationContext.cs" /> | |
144 | <Compile Include="Diagnostics\TraceContext.cs" /> |
|
142 | <Compile Include="Diagnostics\TraceContext.cs" /> | |
145 | <Compile Include="Diagnostics\LogEventArgs.cs" /> |
|
143 | <Compile Include="Diagnostics\LogEventArgs.cs" /> | |
@@ -150,6 +148,8 | |||||
150 | <Compile Include="Parallels\MTCustomQueue.cs" /> |
|
148 | <Compile Include="Parallels\MTCustomQueue.cs" /> | |
151 | <Compile Include="Parallels\MTCustomQueueNode.cs" /> |
|
149 | <Compile Include="Parallels\MTCustomQueueNode.cs" /> | |
152 | <Compile Include="ComponentContainer.cs" /> |
|
150 | <Compile Include="ComponentContainer.cs" /> | |
|
151 | <Compile Include="DisposablePool.cs" /> | |||
|
152 | <Compile Include="ObjectPool.cs" /> | |||
153 | </ItemGroup> |
|
153 | </ItemGroup> | |
154 | <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> |
|
154 | <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> | |
155 | <ItemGroup /> |
|
155 | <ItemGroup /> |
@@ -1,40 +1,35 | |||||
1 | using System; |
|
1 | using Implab.Parallels; | |
2 | using Implab.Parallels; |
|
2 | using System; | |
3 | using System.Threading; |
|
3 | using System.Threading; | |
4 | using System.Diagnostics; |
|
|||
5 | using System.Diagnostics.CodeAnalysis; |
|
|||
6 |
|
4 | |||
7 | namespace Implab { |
|
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 | readonly int m_size; |
|
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")] |
|
25 | protected ObjectPool() : this(Environment.ProcessorCount+1) { | |
13 | static readonly bool _isValueType = typeof(T).IsValueType; |
|
|||
14 |
|
26 | |||
15 | bool m_disposed; |
|
27 | } | |
16 |
|
||||
17 | int m_count; |
|
|||
18 |
|
28 | |||
19 | protected ObjectPool(int size) { |
|
29 | protected ObjectPool(int size) { | |
20 | m_size = size; |
|
30 | Safe.ArgumentInRange(size,1,size,"size"); | |
21 | } |
|
|||
22 |
|
||||
23 | protected ObjectPool() : this(Environment.ProcessorCount+1) { |
|
|||
24 | } |
|
|||
25 |
|
31 | |||
26 | public T Allocate() { |
|
32 | m_size = size; | |
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 | } |
|
33 | } | |
39 |
|
34 | |||
40 | protected abstract T CreateInstance(); |
|
35 | protected abstract T CreateInstance(); | |
@@ -42,49 +37,24 namespace Implab { | |||||
42 | protected virtual void CleanupInstance(T instance) { |
|
37 | protected virtual void CleanupInstance(T instance) { | |
43 | } |
|
38 | } | |
44 |
|
39 | |||
45 |
public |
|
40 | public T Allocate() { | |
46 | if ( Object.Equals(instance,default(T)) && !_isValueType) |
|
41 | WeakReference reference; | |
47 | return; |
|
42 | while (m_queue.TryDequeue(out reference)) { | |
48 |
|
43 | Interlocked.Decrement(ref m_count); | ||
49 | Thread.MemoryBarrier(); |
|
44 | object instance = reference.Target; | |
50 | if (m_count < m_size && !m_disposed) { |
|
45 | if (instance == null) | |
51 | Interlocked.Increment(ref m_count); |
|
46 | continue; | |
52 |
|
47 | return (T)instance; | ||
53 | CleanupInstance(instance); |
|
48 | } | |
|
49 | return CreateInstance(); | |||
|
50 | } | |||
54 |
|
51 | |||
55 | m_queue.Enqueue(instance); |
|
52 | public void Release(T instance) { | |
56 |
|
53 | if (m_count < m_size && instance != null) { | ||
57 | // пока элемент возвращался в кеш, была начата операция освобождения всего кеша |
|
54 | Interlocked.Increment(ref m_count); | |
58 | // и возможно уже законцена, в таком случае следует извлечь элемент обратно и |
|
55 | CleanupInstance(instance); | |
59 | // освободить его. Если операция освобождения кеша еще не заврешилась, то будет |
|
56 | m_queue.Enqueue(new WeakReference(instance)); | |
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 | } |
|
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 | /// <summary> |
|
5 | /// <summary> | |
6 | /// Коллекция сервисов, позволяет регистрировать и получать сервисы. |
|
6 | /// Коллекция сервисов, позволяет регистрировать и получать сервисы. | |
7 | /// </summary> |
|
7 | /// </summary> | |
8 |
public class ServiceLocator: |
|
8 | public class ServiceLocator: Disposable, IServiceLocator, IServiceProvider { | |
9 | // запись о сервисе |
|
9 | // запись о сервисе | |
10 | struct ServiceEntry : IDisposable { |
|
10 | struct ServiceEntry : IDisposable { | |
11 | public object service; // сервис |
|
11 | public object service; // сервис |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
General Comments 0
You need to be logged in to leave comments.
Login now