annotate Implab/AbstractEvent.cs @ 255:b00441e04738 v3

Adde workaround to the behaviour of the logical operations stack in conjuction with async/await methods
author cin
date Wed, 04 Apr 2018 15:38:48 +0300
parents 34df34841225
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
1 using System;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
2 using Implab.Parallels;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
3 using System.Threading;
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
4 using System.Reflection;
242
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
5 using System.Diagnostics;
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
6
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
7 namespace Implab {
243
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
8 /// <summary>
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
9 /// Abstract class for creation of custom one-shot thread safe events.
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
10 /// </summary>
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
11 /// <remarks>
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
12 /// <para>
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
13 /// An event is something that should happen in the future and the
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
14 /// triggering of the event causes execution of some pending actions
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
15 /// which are formely event handlers. One-shot events occur only once
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
16 /// and any handler added after the event is triggered should run
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
17 /// without a delay.
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
18 /// </para>
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
19 /// <para>
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
20 /// The lifecycle of the one-shot event is tipically consists of following
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
21 /// phases.
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
22 /// <list>
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
23 /// <description>Pending state. This is the initial state of the event. Any
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
24 /// handler added to the event will be queued for the future execution.
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
25 /// </description>
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
26 /// <description>Transitional state. This is intermediate state between pending
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
27 /// and fulfilled states, during this state internal initialization and storing
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
28 /// of the result occurs.
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
29 /// </description>
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
30 /// <description>Fulfilled state. The event contains the result, all queued
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
31 /// handlers are signalled to run and newly added handlers are executed
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
32 /// immediatelly.
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
33 /// </description>
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
34 /// </list>
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
35 /// </para>
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
36 /// </remarks>
242
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
37 public abstract class AbstractEvent<THandler> where THandler : class {
244
eee3e49dd1ff working on promises
cin
parents: 243
diff changeset
38 const int PendingState = 0;
242
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
39
244
eee3e49dd1ff working on promises
cin
parents: 243
diff changeset
40 const int TransitionalState = 1;
243
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
41
244
eee3e49dd1ff working on promises
cin
parents: 243
diff changeset
42 const int ResolvedState = 2;
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
43
242
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
44 volatile int m_state;
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
45
242
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
46 THandler m_handler;
233
d6fe09f5592c Improved AsyncQueue
cin
parents: 186
diff changeset
47 SimpleAsyncQueue<THandler> m_extraHandlers;
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
48
244
eee3e49dd1ff working on promises
cin
parents: 243
diff changeset
49 public bool IsResolved {
243
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
50 get {
244
eee3e49dd1ff working on promises
cin
parents: 243
diff changeset
51 return m_state > TransitionalState;
243
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
52 }
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
53 }
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
54
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
55 #region state managment
242
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
56 protected bool BeginTransit() {
244
eee3e49dd1ff working on promises
cin
parents: 243
diff changeset
57 return PendingState == Interlocked.CompareExchange(ref m_state, TransitionalState, PendingState);
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
58 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
59
243
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
60 protected void CompleteTransit() {
242
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
61 #if DEBUG
244
eee3e49dd1ff working on promises
cin
parents: 243
diff changeset
62 if (TransitionalState != Interlocked.CompareExchange(ref m_state, ResolvedState, TransitionalState))
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
63 throw new InvalidOperationException("Can't complete transition when the object isn't in the transitional state");
242
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
64 #else
253
34df34841225 Implab.Diagnostics drafts
cin
parents: 248
diff changeset
65 m_state = ResolvedState;
242
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
66 #endif
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
67 Signal();
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
68 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
69
242
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
70 protected void WaitTransition() {
244
eee3e49dd1ff working on promises
cin
parents: 243
diff changeset
71 if (m_state == TransitionalState) {
248
5cb4826c2c2a Added awaiters to promises
cin
parents: 244
diff changeset
72 SpinWait spin = new SpinWait();
242
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
73 do {
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
74 spin.SpinOnce();
244
eee3e49dd1ff working on promises
cin
parents: 243
diff changeset
75 } while (m_state == TransitionalState);
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
76 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
77 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
78
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
79
243
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
80 protected abstract void SignalHandler(THandler handler);
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
81
156
97fbbf816844 Promises: SignalXXX methods merged into SignalHandler method.
cin
parents: 148
diff changeset
82 void Signal() {
242
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
83 THandler handler;
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
84 while (TryDequeueHandler(out handler))
243
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
85 SignalHandler(handler);
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
86 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
87
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
88 #endregion
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
89
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
90 #region handlers managment
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
91
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
92 protected void AddHandler(THandler handler) {
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
93
244
eee3e49dd1ff working on promises
cin
parents: 243
diff changeset
94 if (IsResolved) {
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
95 // the promise is in the resolved state, just invoke the handler
243
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
96 SignalHandler(handler);
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
97 } else {
243
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
98 EnqueueHandler(handler);
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
99
244
eee3e49dd1ff working on promises
cin
parents: 243
diff changeset
100 if (IsResolved && TryDequeueHandler(out handler))
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
101 // if the promise have been resolved while we was adding the handler to the queue
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
102 // we can't guarantee that someone is still processing it
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
103 // therefore we need to fetch a handler from the queue and execute it
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
104 // note that fetched handler may be not the one that we have added
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
105 // even we can fetch no handlers at all :)
243
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
106 SignalHandler(handler);
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
107 }
242
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
108
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
109 }
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
110
243
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
111 void EnqueueHandler(THandler handler) {
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
112 if (Interlocked.CompareExchange(ref m_handler, handler, null) != null) {
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
113 if (m_extraHandlers == null)
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
114 // compare-exchange will protect from loosing already created queue
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
115 Interlocked.CompareExchange(ref m_extraHandlers, new SimpleAsyncQueue<THandler>(), null);
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
116 m_extraHandlers.Enqueue(handler);
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
117 }
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
118 }
b1e0ffdf3451 working on promises
cin
parents: 242
diff changeset
119
242
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
120 bool TryDequeueHandler(out THandler handler) {
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
121 handler = Interlocked.Exchange(ref m_handler, null);
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
122 if (handler != null)
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
123 return true;
cbe10ac0731e Working on promises
cin
parents: 240
diff changeset
124 return m_extraHandlers != null && m_extraHandlers.TryDequeue(out handler);
144
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
125 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
126
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
127 #endregion
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
128 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
129 }
8c0b95069066 DRAFT: refactoring
cin
parents:
diff changeset
130