##// END OF EJS Templates
Removed obsolete App, ComponentContainer...
cin -
r256:c52691faaf21 v3
parent child
Show More
@@ -0,0 +1,37
1 using System;
2 using System.Threading.Tasks;
3
4 namespace Implab.Components {
5 /// <summary>
6 /// An interface for asynchronous components.
7 /// </summary>
8 /// <remarks>
9 /// <para>
10 /// Асинхронные компоненты не предназначены для одновременного использования несколькими клиентами,
11 /// однако существуют внутренние процессы, изменяющее состояние компонент без участия клиента.
12 /// Данный интерфейс определяет протокол взаимодействия с компонентой, при которм компоненте
13 /// посылаются сигналы от клиента, в ответ на которые компонента меняет свойство <see cref="Completion"/>,
14 /// данное свойство содержит в себе новую задачу, выполняемую компонентой и данное свойство
15 /// может измениться только при получении нового сигнала от клиента.
16 /// </para>
17 /// <para>
18 /// В дополнение к <see cref="Completion"/> компонента может определять другие свойства, в
19 /// которых будет передаваться информация о результате выполнения операции.
20 /// </para>
21 /// <para>
22 /// Особое внимание следует уделить реализации <see cref="IDisposable"/>, который по своей природе
23 /// синхронный, данное правило безусловно можно нарушить, но тогда могут возникнуть проблемы с
24 /// тем, что ресурсы еще не освободились, а ход программы продолжается, что приведет к ошибкам,
25 /// например при попытке получить ресуср другим объектом, либо при заврешении программы.
26 /// </para>
27 /// <seealso href="https://blog.stephencleary.com/2013/01/async-oop-0-introduction.html"/>
28 /// </remarks>
29 public interface IAsyncComponent {
30 /// <summary>
31 /// The result of the last started operation. This property reflects
32 /// only the result of the last started operation and therefore should
33 /// change only if a new operation is initiated.
34 /// </summary>
35 Task Completion { get; }
36 }
37 } No newline at end of file
@@ -2,7 +2,7
2
2
3 <PropertyGroup>
3 <PropertyGroup>
4 <TargetFramework>net46</TargetFramework>
4 <TargetFramework>net46</TargetFramework>
5 <FrameworkPathOverride Condition="'$(TargetFramework)'=='net45' and '$(OSTYPE)'=='linux'">/usr/lib/mono/4.5/</FrameworkPathOverride>
5 <FrameworkPathOverride Condition="'$(TargetFramework)'=='net46' and '$(OSTYPE)'=='linux'">/usr/lib/mono/4.5/</FrameworkPathOverride>
6
6
7 <IsPackable>false</IsPackable>
7 <IsPackable>false</IsPackable>
8 </PropertyGroup>
8 </PropertyGroup>
@@ -2,6 +2,7 using System;
2 using System.Diagnostics;
2 using System.Diagnostics;
3 using System.Threading;
3 using System.Threading;
4 using Implab.Diagnostics;
4 using Implab.Diagnostics;
5 using System.Linq;
5 using Xunit;
6 using Xunit;
6
7
7 namespace Implab.Test {
8 namespace Implab.Test {
@@ -11,19 +12,29 namespace Implab.Test {
11 [Fact]
12 [Fact]
12 public async Task Test1() {
13 public async Task Test1() {
13 var listener = new SimpleTraceListener(Console.Out);
14 var listener = new SimpleTraceListener(Console.Out);
15 listener.TraceOutputOptions |= TraceOptions.ThreadId;
14
16
15 var source = TraceSource;
17 var source = TraceSource;
16 source.Switch.Level = SourceLevels.All;
18 source.Switch.Level = SourceLevels.All;
17
19
18 source.Listeners.Add(listener);
20 source.Listeners.Add(listener);
19
21
20 using (var op = LogicalOperation(nameof(Test1)))
22 using (LogicalOperation("Test1")){
21 using (LogicalOperation("InnerOperation")){
22 await Task.Yield();
23 await Task.Yield();
23 Log("Inner");
24 Log(String.Join(", ", Trace.CorrelationManager.LogicalOperationStack.Cast<object>().Select(x => x.ToString())));
24 await Task.Yield();
25 await AsyncDummy();
25 Log("source event");
26 Log(String.Join(", ", Trace.CorrelationManager.LogicalOperationStack.Cast<object>().Select(x => x.ToString())));
27 }
28 }
29
30 async Task AsyncDummy() {
31 using(LogicalOperation("OuterDummy"))
32 using(LogicalOperation("InnerDummy")) {
33 Log(String.Join(", ", Trace.CorrelationManager.LogicalOperationStack.Cast<object>().Select(x => x.ToString())));
34 await Task.Delay(1);
35 Log(String.Join(", ", Trace.CorrelationManager.LogicalOperationStack.Cast<object>().Select(x => x.ToString())));
36 }
37 Log(String.Join(", ", Trace.CorrelationManager.LogicalOperationStack.Cast<object>().Select(x => x.ToString())));
26 }
38 }
27 }
39 }
28 }
40 }
29 }
@@ -6,10 +6,10 using System.Diagnostics.CodeAnalysis;
6
6
7 namespace Implab.Components {
7 namespace Implab.Components {
8 /// <summary>
8 /// <summary>
9 /// The base class for implementing pools of disposable objects.
9 /// The base class for implementing thread-safe pools of disposable objects.
10 /// </summary>
10 /// </summary>
11 /// <remarks>
11 /// <remarks>
12 /// <para>This class maintains a set of pre-created objects and which are frequently allocated and released
12 /// <para>This class maintains a set of pre-created objects which are frequently allocated and released
13 /// by clients. The pool maintains maximum number of unsued object, any object above this limit is disposed,
13 /// by clients. The pool maintains maximum number of unsued object, any object above this limit is disposed,
14 /// if the pool is empty it will create new objects on demand.</para>
14 /// if the pool is empty it will create new objects on demand.</para>
15 /// <para>Instances of this class are thread-safe.</para>
15 /// <para>Instances of this class are thread-safe.</para>
@@ -34,14 +34,7 namespace Implab.Components {
34 void Stop(CancellationToken ct);
34 void Stop(CancellationToken ct);
35
35
36 /// <summary>
36 /// <summary>
37 /// The result of the last started operation. This property reflects
37 /// Current state of the componenet, dynamically reflects the current state.
38 /// only the result of the last started operation and therefore should
39 /// change only if a new operation is initiated.
40 /// </summary>
41 Task Completion { get; }
42
43 /// <summary>
44 /// Current state of the componenet
45 /// </summary>
38 /// </summary>
46 ExecutionState State { get; }
39 ExecutionState State { get; }
47
40
@@ -12,7 +12,7 namespace Implab.Components {
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 : IRunnable, IInitializable, IDisposable {
15 public 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,
@@ -80,7 +80,7 namespace Implab.Components {
80 }
80 }
81
81
82 // this lock is used to synchronize state flow of the component during
82 // this lock is used to synchronize state flow of the component during
83 // completions or the operations.
83 // processing calls from a client and internal processes.
84 readonly object m_lock = new object();
84 readonly object m_lock = new object();
85
85
86 // current operation cookie, used to check wheather a call to
86 // current operation cookie, used to check wheather a call to
@@ -88,6 +88,7 namespace Implab.Components {
88 // operation, if cookies didn't match ignore completion result.
88 // operation, if cookies didn't match ignore completion result.
89 object m_cookie;
89 object m_cookie;
90
90
91 // AsyncOperationDscriptor aggregates a task and it's cancellation token
91 AsyncOperationDescriptor m_current = AsyncOperationDescriptor.None;
92 AsyncOperationDescriptor m_current = AsyncOperationDescriptor.None;
92
93
93 ExecutionState m_state;
94 ExecutionState m_state;
@@ -152,6 +153,8 namespace Implab.Components {
152 var cookie = new object();
153 var cookie = new object();
153 if (MoveInitialize(cookie))
154 if (MoveInitialize(cookie))
154 ScheduleTask(InitializeInternalAsync, CancellationToken.None, cookie);
155 ScheduleTask(InitializeInternalAsync, CancellationToken.None, cookie);
156 else
157 throw new InvalidOperationException();
155 }
158 }
156
159
157 /// <summary>
160 /// <summary>
@@ -171,6 +174,8 namespace Implab.Components {
171 var cookie = new object();
174 var cookie = new object();
172 if (MoveStart(cookie))
175 if (MoveStart(cookie))
173 ScheduleTask(StartInternalAsync, ct, cookie);
176 ScheduleTask(StartInternalAsync, ct, cookie);
177 else
178 throw new InvalidOperationException();
174 }
179 }
175
180
176 protected virtual Task StartInternalAsync(CancellationToken ct) {
181 protected virtual Task StartInternalAsync(CancellationToken ct) {
@@ -181,6 +186,8 namespace Implab.Components {
181 var cookie = new object();
186 var cookie = new object();
182 if (MoveStop(cookie))
187 if (MoveStop(cookie))
183 ScheduleTask(StopAsync, ct, cookie);
188 ScheduleTask(StopAsync, ct, cookie);
189 else
190 throw new InvalidOperationException();
184 }
191 }
185
192
186 async Task StopAsync(CancellationToken ct) {
193 async Task StopAsync(CancellationToken ct) {
@@ -196,6 +203,16 namespace Implab.Components {
196 return Task.CompletedTask;
203 return Task.CompletedTask;
197 }
204 }
198
205
206 protected void Fail(Exception err) {
207 lock(m_lock) {
208 if (m_state != ExecutionState.Running)
209 return;
210 m_cookie = new object();
211 LastError = err;
212 State = ExecutionState.Failed;
213 }
214 }
215
199
216
200 #region state management
217 #region state management
201
218
@@ -256,16 +273,16 namespace Implab.Components {
256 }
273 }
257 }
274 }
258
275
259
276 void ScheduleTask(Func<CancellationToken, Task> next, CancellationToken ct, object cookie) {
260
277
261 protected async void ScheduleTask(Func<CancellationToken, Task> next, CancellationToken ct, object cookie) {
278 m_current = AsyncOperationDescriptor.Create(async (x) => {
262 try {
279 try {
263 m_current = AsyncOperationDescriptor.Create(next, ct);
280 await next(x);
264 await m_current.Task;
265 MoveSuccess(cookie);
281 MoveSuccess(cookie);
266 } catch (Exception e) {
282 } catch (Exception e) {
267 MoveFailed(e, cookie);
283 MoveFailed(e, cookie);
268 }
284 }
285 }, ct);
269 }
286 }
270
287
271 #endregion
288 #endregion
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 3
Under Review
author

Auto status change to "Under Review"

Approved
author

ok, latest stable version should be in default

You need to be logged in to leave comments. Login now