##// 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 3 <PropertyGroup>
4 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 7 <IsPackable>false</IsPackable>
8 8 </PropertyGroup>
@@ -2,6 +2,7 using System;
2 2 using System.Diagnostics;
3 3 using System.Threading;
4 4 using Implab.Diagnostics;
5 using System.Linq;
5 6 using Xunit;
6 7
7 8 namespace Implab.Test {
@@ -11,19 +12,29 namespace Implab.Test {
11 12 [Fact]
12 13 public async Task Test1() {
13 14 var listener = new SimpleTraceListener(Console.Out);
15 listener.TraceOutputOptions |= TraceOptions.ThreadId;
14 16
15 17 var source = TraceSource;
16 18 source.Switch.Level = SourceLevels.All;
17 19
18 20 source.Listeners.Add(listener);
19 21
20 using (var op = LogicalOperation(nameof(Test1)))
21 using (LogicalOperation("InnerOperation")){
22 using (LogicalOperation("Test1")){
22 23 await Task.Yield();
23 Log("Inner");
24 await Task.Yield();
25 Log("source event");
24 Log(String.Join(", ", Trace.CorrelationManager.LogicalOperationStack.Cast<object>().Select(x => x.ToString())));
25 await AsyncDummy();
26 Log(String.Join(", ", Trace.CorrelationManager.LogicalOperationStack.Cast<object>().Select(x => x.ToString())));
26 27 }
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())));
38 }
28 39 }
29 40 }
@@ -6,10 +6,10 using System.Diagnostics.CodeAnalysis;
6 6
7 7 namespace Implab.Components {
8 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 10 /// </summary>
11 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 13 /// by clients. The pool maintains maximum number of unsued object, any object above this limit is disposed,
14 14 /// if the pool is empty it will create new objects on demand.</para>
15 15 /// <para>Instances of this class are thread-safe.</para>
@@ -34,14 +34,7 namespace Implab.Components {
34 34 void Stop(CancellationToken ct);
35 35
36 36 /// <summary>
37 /// The result of the last started operation. This property reflects
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
37 /// Current state of the componenet, dynamically reflects the current state.
45 38 /// </summary>
46 39 ExecutionState State { get; }
47 40
@@ -12,7 +12,7 namespace Implab.Components {
12 12 /// This class provides a basic lifecycle from the creation to the
13 13 /// termination of the component.
14 14 /// </remarks>
15 public class RunnableComponent : IRunnable, IInitializable, IDisposable {
15 public class RunnableComponent : IAsyncComponent, IRunnable, IInitializable, IDisposable {
16 16
17 17 /// <summary>
18 18 /// This class bounds <see cref="CancellationTokenSource"/> lifetime to the task,
@@ -80,7 +80,7 namespace Implab.Components {
80 80 }
81 81
82 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 84 readonly object m_lock = new object();
85 85
86 86 // current operation cookie, used to check wheather a call to
@@ -88,6 +88,7 namespace Implab.Components {
88 88 // operation, if cookies didn't match ignore completion result.
89 89 object m_cookie;
90 90
91 // AsyncOperationDscriptor aggregates a task and it's cancellation token
91 92 AsyncOperationDescriptor m_current = AsyncOperationDescriptor.None;
92 93
93 94 ExecutionState m_state;
@@ -152,6 +153,8 namespace Implab.Components {
152 153 var cookie = new object();
153 154 if (MoveInitialize(cookie))
154 155 ScheduleTask(InitializeInternalAsync, CancellationToken.None, cookie);
156 else
157 throw new InvalidOperationException();
155 158 }
156 159
157 160 /// <summary>
@@ -171,6 +174,8 namespace Implab.Components {
171 174 var cookie = new object();
172 175 if (MoveStart(cookie))
173 176 ScheduleTask(StartInternalAsync, ct, cookie);
177 else
178 throw new InvalidOperationException();
174 179 }
175 180
176 181 protected virtual Task StartInternalAsync(CancellationToken ct) {
@@ -181,6 +186,8 namespace Implab.Components {
181 186 var cookie = new object();
182 187 if (MoveStop(cookie))
183 188 ScheduleTask(StopAsync, ct, cookie);
189 else
190 throw new InvalidOperationException();
184 191 }
185 192
186 193 async Task StopAsync(CancellationToken ct) {
@@ -196,6 +203,16 namespace Implab.Components {
196 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 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) {
262 try {
263 m_current = AsyncOperationDescriptor.Create(next, ct);
264 await m_current.Task;
265 MoveSuccess(cookie);
266 } catch (Exception e) {
267 MoveFailed(e, cookie);
268 }
278 m_current = AsyncOperationDescriptor.Create(async (x) => {
279 try {
280 await next(x);
281 MoveSuccess(cookie);
282 } catch (Exception e) {
283 MoveFailed(e, cookie);
284 }
285 }, ct);
269 286 }
270 287
271 288 #endregion
1 NO CONTENT: file was removed
1 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