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