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 }