Mercurial > pub > ImplabNet
comparison Implab/Components/RunnableComponent.cs @ 257:440801d88019 v3
working on runnable components
author | cin |
---|---|
date | Fri, 13 Apr 2018 00:43:10 +0300 |
parents | c52691faaf21 |
children | 547a2fc0d93e |
comparison
equal
deleted
inserted
replaced
256:c52691faaf21 | 257:440801d88019 |
---|---|
10 /// </summary> | 10 /// </summary> |
11 /// <remarks> | 11 /// <remarks> |
12 /// This class provides a basic lifecycle from the creation to the | 12 /// This class provides a basic lifecycle from the creation to the |
13 /// termination of the component. | 13 /// termination of the component. |
14 /// </remarks> | 14 /// </remarks> |
15 public class RunnableComponent : IAsyncComponent, IRunnable, IInitializable, IDisposable { | 15 public abstract class RunnableComponent : IAsyncComponent, IRunnable, IInitializable, IDisposable { |
16 | 16 |
17 /// <summary> | 17 /// <summary> |
18 /// This class bounds <see cref="CancellationTokenSource"/> lifetime to the task, | 18 /// This class bounds <see cref="CancellationTokenSource"/> lifetime to the task, |
19 /// when the task completes the associated token source will be disposed. | 19 /// when the task completes the associated token source will be disposed. |
20 /// </summary> | 20 /// </summary> |
91 // AsyncOperationDscriptor aggregates a task and it's cancellation token | 91 // AsyncOperationDscriptor aggregates a task and it's cancellation token |
92 AsyncOperationDescriptor m_current = AsyncOperationDescriptor.None; | 92 AsyncOperationDescriptor m_current = AsyncOperationDescriptor.None; |
93 | 93 |
94 ExecutionState m_state; | 94 ExecutionState m_state; |
95 | 95 |
96 /// <summary> | |
97 /// Объект синхронизации используется для обеспечения совместного доступа | |
98 /// клиента компоненты и процессов, протекающих внутри компоненты, к общему | |
99 /// состоянию, т.е.true таким свойствам, как <see cref="State"/>, | |
100 /// <see cref="LastError"/>. Обработчики события <see cref="StateChanged"/> | |
101 /// вызываются уже с установленной блокировкой, поэтому дополнительная | |
102 /// синхронизация не требуется. | |
103 /// </summary> | |
104 public object SynchronizationObject { get { return m_lock; } } | |
96 | 105 |
97 protected RunnableComponent(bool initialized) { | 106 protected RunnableComponent(bool initialized) { |
98 State = initialized ? ExecutionState.Ready : ExecutionState.Created; | 107 State = initialized ? ExecutionState.Ready : ExecutionState.Created; |
99 } | 108 } |
100 | 109 |
115 } | 124 } |
116 } | 125 } |
117 | 126 |
118 public Exception LastError { get; private set; } | 127 public Exception LastError { get; private set; } |
119 | 128 |
129 /// <summary> | |
130 /// Событие изменения состояния компоненты.see Обработчики данного события | |
131 /// вызываются внутри блокировки <see cref="SynchronizationObject"/> и должны | |
132 /// выполняться максимально быстро. | |
133 /// </summary> | |
120 public event EventHandler<StateChangeEventArgs> StateChanged; | 134 public event EventHandler<StateChangeEventArgs> StateChanged; |
121 | 135 |
122 /// <summary> | 136 /// <summary> |
123 /// Releases all resources used by the current component regardless of its | 137 /// Releases all resources used by the current component regardless of its |
124 /// execution state. | 138 /// execution state. |
128 /// isn't in the stopped state. Call this method after the component is | 142 /// isn't in the stopped state. Call this method after the component is |
129 /// stopped if needed or if the component is in the failed state. | 143 /// stopped if needed or if the component is in the failed state. |
130 /// </remarks> | 144 /// </remarks> |
131 public void Dispose() { | 145 public void Dispose() { |
132 bool dispose = false; | 146 bool dispose = false; |
147 lock (SynchronizationObject) { | |
148 if (m_state != ExecutionState.Disposed) { | |
149 dispose = true; | |
150 m_state = ExecutionState.Disposed; | |
151 m_cookie = new object(); | |
152 } | |
153 } | |
133 if (dispose) { | 154 if (dispose) { |
134 Dispose(true); | 155 Dispose(true); |
135 GC.SuppressFinalize(this); | 156 GC.SuppressFinalize(this); |
136 } | 157 } |
137 } | 158 } |
150 } | 171 } |
151 | 172 |
152 public void Initialize() { | 173 public void Initialize() { |
153 var cookie = new object(); | 174 var cookie = new object(); |
154 if (MoveInitialize(cookie)) | 175 if (MoveInitialize(cookie)) |
155 ScheduleTask(InitializeInternalAsync, CancellationToken.None, cookie); | 176 Safe.NoWait(ScheduleTask(InitializeInternalAsync, CancellationToken.None, cookie)); |
156 else | 177 else |
157 throw new InvalidOperationException(); | 178 throw new InvalidOperationException(); |
158 } | 179 } |
159 | 180 |
160 /// <summary> | 181 /// <summary> |
171 } | 192 } |
172 | 193 |
173 public void Start(CancellationToken ct) { | 194 public void Start(CancellationToken ct) { |
174 var cookie = new object(); | 195 var cookie = new object(); |
175 if (MoveStart(cookie)) | 196 if (MoveStart(cookie)) |
176 ScheduleTask(StartInternalAsync, ct, cookie); | 197 Safe.NoWait(ScheduleStartAndRun(ct, cookie)); |
177 else | 198 else |
178 throw new InvalidOperationException(); | 199 throw new InvalidOperationException(); |
179 } | 200 } |
180 | 201 |
202 async Task ScheduleStartAndRun(CancellationToken ct, object cookie) { | |
203 try { | |
204 await ScheduleTask(StartInternalAsync, ct, cookie); | |
205 RunInternal(); | |
206 } catch (Exception err) { | |
207 Fail(err); | |
208 } | |
209 } | |
210 | |
181 protected virtual Task StartInternalAsync(CancellationToken ct) { | 211 protected virtual Task StartInternalAsync(CancellationToken ct) { |
182 return Task.CompletedTask; | 212 return Task.CompletedTask; |
213 } | |
214 | |
215 /// <summary> | |
216 /// This method is called after the component is enetered running state, | |
217 /// use this method to | |
218 /// </summary> | |
219 protected virtual void RunInternal() { | |
220 | |
183 } | 221 } |
184 | 222 |
185 public void Stop(CancellationToken ct) { | 223 public void Stop(CancellationToken ct) { |
186 var cookie = new object(); | 224 var cookie = new object(); |
187 if (MoveStop(cookie)) | 225 if (MoveStop(cookie)) |
188 ScheduleTask(StopAsync, ct, cookie); | 226 Safe.NoWait(ScheduleTask(StopAsync, ct, cookie)); |
189 else | 227 else |
190 throw new InvalidOperationException(); | 228 throw new InvalidOperationException(); |
191 } | 229 } |
192 | 230 |
193 async Task StopAsync(CancellationToken ct) { | 231 async Task StopAsync(CancellationToken ct) { |
271 LastError = err; | 309 LastError = err; |
272 State = ExecutionState.Failed; | 310 State = ExecutionState.Failed; |
273 } | 311 } |
274 } | 312 } |
275 | 313 |
276 void ScheduleTask(Func<CancellationToken, Task> next, CancellationToken ct, object cookie) { | 314 Task ScheduleTask(Func<CancellationToken, Task> next, CancellationToken ct, object cookie) { |
277 | 315 |
278 m_current = AsyncOperationDescriptor.Create(async (x) => { | 316 var op = AsyncOperationDescriptor.Create(async (x) => { |
279 try { | 317 try { |
280 await next(x); | 318 await next(x); |
281 MoveSuccess(cookie); | 319 MoveSuccess(cookie); |
282 } catch (Exception e) { | 320 } catch (Exception e) { |
283 MoveFailed(e, cookie); | 321 MoveFailed(e, cookie); |
284 } | 322 } |
285 }, ct); | 323 }, ct); |
324 | |
325 m_current = op; | |
326 return op.Task; | |
286 } | 327 } |
287 | 328 |
288 #endregion | 329 #endregion |
289 } | 330 } |
290 } | 331 } |