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 } |
