Mercurial > pub > ImplabNet
diff 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 |
line wrap: on
line diff
--- a/Implab/Components/RunnableComponent.cs Wed Apr 11 03:05:14 2018 +0300 +++ b/Implab/Components/RunnableComponent.cs Fri Apr 13 00:43:10 2018 +0300 @@ -12,7 +12,7 @@ /// This class provides a basic lifecycle from the creation to the /// termination of the component. /// </remarks> - public class RunnableComponent : IAsyncComponent, IRunnable, IInitializable, IDisposable { + public abstract class RunnableComponent : IAsyncComponent, IRunnable, IInitializable, IDisposable { /// <summary> /// This class bounds <see cref="CancellationTokenSource"/> lifetime to the task, @@ -93,6 +93,15 @@ ExecutionState m_state; + /// <summary> + /// Объект синхронизации используется для обеспечения совместного доступа + /// клиента компоненты и процессов, протекающих внутри компоненты, к общему + /// состоянию, т.е.true таким свойствам, как <see cref="State"/>, + /// <see cref="LastError"/>. Обработчики события <see cref="StateChanged"/> + /// вызываются уже с установленной блокировкой, поэтому дополнительная + /// синхронизация не требуется. + /// </summary> + public object SynchronizationObject { get { return m_lock; } } protected RunnableComponent(bool initialized) { State = initialized ? ExecutionState.Ready : ExecutionState.Created; @@ -117,6 +126,11 @@ public Exception LastError { get; private set; } + /// <summary> + /// Событие изменения состояния компоненты.see Обработчики данного события + /// вызываются внутри блокировки <see cref="SynchronizationObject"/> и должны + /// выполняться максимально быстро. + /// </summary> public event EventHandler<StateChangeEventArgs> StateChanged; /// <summary> @@ -130,6 +144,13 @@ /// </remarks> public void Dispose() { bool dispose = false; + lock (SynchronizationObject) { + if (m_state != ExecutionState.Disposed) { + dispose = true; + m_state = ExecutionState.Disposed; + m_cookie = new object(); + } + } if (dispose) { Dispose(true); GC.SuppressFinalize(this); @@ -152,7 +173,7 @@ public void Initialize() { var cookie = new object(); if (MoveInitialize(cookie)) - ScheduleTask(InitializeInternalAsync, CancellationToken.None, cookie); + Safe.NoWait(ScheduleTask(InitializeInternalAsync, CancellationToken.None, cookie)); else throw new InvalidOperationException(); } @@ -173,19 +194,36 @@ public void Start(CancellationToken ct) { var cookie = new object(); if (MoveStart(cookie)) - ScheduleTask(StartInternalAsync, ct, cookie); + Safe.NoWait(ScheduleStartAndRun(ct, cookie)); else throw new InvalidOperationException(); } + async Task ScheduleStartAndRun(CancellationToken ct, object cookie) { + try { + await ScheduleTask(StartInternalAsync, ct, cookie); + RunInternal(); + } catch (Exception err) { + Fail(err); + } + } + protected virtual Task StartInternalAsync(CancellationToken ct) { return Task.CompletedTask; } + /// <summary> + /// This method is called after the component is enetered running state, + /// use this method to + /// </summary> + protected virtual void RunInternal() { + + } + public void Stop(CancellationToken ct) { var cookie = new object(); if (MoveStop(cookie)) - ScheduleTask(StopAsync, ct, cookie); + Safe.NoWait(ScheduleTask(StopAsync, ct, cookie)); else throw new InvalidOperationException(); } @@ -273,9 +311,9 @@ } } - void ScheduleTask(Func<CancellationToken, Task> next, CancellationToken ct, object cookie) { + Task ScheduleTask(Func<CancellationToken, Task> next, CancellationToken ct, object cookie) { - m_current = AsyncOperationDescriptor.Create(async (x) => { + var op = AsyncOperationDescriptor.Create(async (x) => { try { await next(x); MoveSuccess(cookie); @@ -283,6 +321,9 @@ MoveFailed(e, cookie); } }, ct); + + m_current = op; + return op.Task; } #endregion