##// END OF EJS Templates
Working on promises
cin -
r242:cbe10ac0731e v3
parent child
Show More
@@ -195,7 +195,7 namespace Implab.Fx {
195
195
196 protected override void Dispose(bool disposing) {
196 protected override void Dispose(bool disposing) {
197 if (disposing) {
197 if (disposing) {
198 if (!m_threadTerminated.IsResolved)
198 if (!m_threadTerminated.IsFulfilled)
199 m_syncContext.Post(x => Application.ExitThread(), null);
199 m_syncContext.Post(x => Application.ExitThread(), null);
200 }
200 }
201 base.Dispose(disposing);
201 base.Dispose(disposing);
@@ -40,7 +40,7 namespace Implab.Test {
40 // cancel the promise
40 // cancel the promise
41 Assert.IsTrue(p.CancelOperationIfRequested());
41 Assert.IsTrue(p.CancelOperationIfRequested());
42 Assert.IsTrue(p.IsCancelled);
42 Assert.IsTrue(p.IsCancelled);
43 Assert.AreSame(reason, p.Error);
43 Assert.AreSame(reason, p.RejectReason);
44 }
44 }
45
45
46 [TestMethod]
46 [TestMethod]
@@ -76,7 +76,7 namespace Implab.Test {
76 task.Cancel();
76 task.Cancel();
77 Assert.IsTrue(task.IsCancellationRequested);
77 Assert.IsTrue(task.IsCancellationRequested);
78 Assert.IsFalse(task.IsCancelled);
78 Assert.IsFalse(task.IsCancelled);
79 Assert.IsFalse(task.IsResolved);
79 Assert.IsFalse(task.IsFulfilled);
80
80
81 finish.Set();
81 finish.Set();
82 task.Join(1000);
82 task.Join(1000);
@@ -2,56 +2,50
2 using Implab.Parallels;
2 using Implab.Parallels;
3 using System.Threading;
3 using System.Threading;
4 using System.Reflection;
4 using System.Reflection;
5 using System.Diagnostics;
5
6
6 namespace Implab {
7 namespace Implab {
7 public abstract class AbstractEvent<THandler> : ICancellable {
8 public abstract class AbstractEvent<THandler> where THandler : class {
8
9
9 const int UNRESOLVED_SATE = 0;
10 const int PENDING_SATE = 0;
10 const int TRANSITIONAL_STATE = 1;
11 protected const int TRANSITIONAL_STATE = 1;
12
11 protected const int SUCCEEDED_STATE = 2;
13 protected const int SUCCEEDED_STATE = 2;
12 protected const int REJECTED_STATE = 3;
14 protected const int REJECTED_STATE = 3;
13 protected const int CANCELLED_STATE = 4;
14
15
15 const int CANCEL_NOT_REQUESTED = 0;
16 volatile int m_state;
16 const int CANCEL_REQUESTING = 1;
17 const int CANCEL_REQUESTED = 2;
18
19 const int RESERVED_HANDLERS_COUNT = 4;
20
21 int m_state;
22 Exception m_error;
17 Exception m_error;
23 int m_handlersCount;
24
18
25 //readonly THandler[] m_handlers = new THandler[RESERVED_HANDLERS_COUNT];
19 THandler m_handler;
26 THandler[] m_handlers;
27 SimpleAsyncQueue<THandler> m_extraHandlers;
20 SimpleAsyncQueue<THandler> m_extraHandlers;
28 int m_handlerPointer = -1;
29 int m_handlersCommited;
30
31 int m_cancelRequest;
32 Exception m_cancelationReason;
33
21
34 #region state managment
22 #region state managment
35 bool BeginTransit() {
23 protected bool BeginTransit() {
36 return UNRESOLVED_SATE == Interlocked.CompareExchange(ref m_state, TRANSITIONAL_STATE, UNRESOLVED_SATE);
24 return PENDING_SATE == Interlocked.CompareExchange(ref m_state, TRANSITIONAL_STATE, PENDING_SATE);
37 }
25 }
38
26
39 void CompleteTransit(int state) {
27 protected void CompleteTransit(int state) {
28 #if DEBUG
40 if (TRANSITIONAL_STATE != Interlocked.CompareExchange(ref m_state, state, TRANSITIONAL_STATE))
29 if (TRANSITIONAL_STATE != Interlocked.CompareExchange(ref m_state, state, TRANSITIONAL_STATE))
41 throw new InvalidOperationException("Can't complete transition when the object isn't in the transitional state");
30 throw new InvalidOperationException("Can't complete transition when the object isn't in the transitional state");
31 #else
32 m_state = state;
33 #endif
34 Signal();
42 }
35 }
43
36
44 void WaitTransition() {
37 protected void WaitTransition() {
45 while (m_state == TRANSITIONAL_STATE) {
38 if (m_state == TRANSITIONAL_STATE) {
46 Thread.MemoryBarrier();
39 SpinWait spin;
40 do {
41 spin.SpinOnce();
42 } while (m_state == TRANSITIONAL_STATE);
47 }
43 }
48 }
44 }
49
45
50 protected bool BeginSetResult() {
46 protected bool BeginSetResult() {
51 if (!BeginTransit()) {
47 if (!BeginTransit()) {
52 WaitTransition();
48 WaitTransition();
53 if (m_state != CANCELLED_STATE)
54 throw new InvalidOperationException("The promise is already resolved");
55 return false;
49 return false;
56 }
50 }
57 return true;
51 return true;
@@ -59,7 +53,6 namespace Implab {
59
53
60 protected void EndSetResult() {
54 protected void EndSetResult() {
61 CompleteTransit(SUCCEEDED_STATE);
55 CompleteTransit(SUCCEEDED_STATE);
62 Signal();
63 }
56 }
64
57
65
58
@@ -78,8 +71,6 namespace Implab {
78 if (BeginTransit()) {
71 if (BeginTransit()) {
79 m_error = error;
72 m_error = error;
80 CompleteTransit(REJECTED_STATE);
73 CompleteTransit(REJECTED_STATE);
81
82 Signal();
83 } else {
74 } else {
84 WaitTransition();
75 WaitTransition();
85 if (m_state == SUCCEEDED_STATE)
76 if (m_state == SUCCEEDED_STATE)
@@ -87,58 +78,33 namespace Implab {
87 }
78 }
88 }
79 }
89
80
90 /// <summary>
91 /// Отменяет операцию, если это возможно.
92 /// </summary>
93 /// <remarks>Для определения была ли операция отменена следует использовать свойство <see cref="IsCancelled"/>.</remarks>
94 protected void SetCancelled(Exception reason) {
95 if (BeginTransit()) {
96 m_error = reason;
97 CompleteTransit(CANCELLED_STATE);
98 Signal();
99 }
100 }
101
102 protected abstract void SignalHandler(THandler handler, int signal);
81 protected abstract void SignalHandler(THandler handler, int signal);
103
82
104 void Signal() {
83 void Signal() {
105 var hp = m_handlerPointer;
84 THandler handler;
106 var slot = hp +1 ;
85 while (TryDequeueHandler(out handler))
107 while (slot < m_handlersCommited) {
86 SignalHandler(handler, m_state);
108 if (Interlocked.CompareExchange(ref m_handlerPointer, slot, hp) == hp) {
109 SignalHandler(m_handlers[slot], m_state);
110 }
111 hp = m_handlerPointer;
112 slot = hp +1 ;
113 }
114
115
116 if (m_extraHandlers != null) {
117 THandler handler;
118 while (m_extraHandlers.TryDequeue(out handler))
119 SignalHandler(handler, m_state);
120 }
121 }
87 }
122
88
123 #endregion
89 #endregion
124
90
125 protected abstract Signal GetResolveSignal();
91 protected abstract Signal GetFulfillSignal();
126
92
127 #region synchronization traits
93 #region synchronization traits
128 protected void WaitResult(int timeout) {
94 protected void WaitResult(int timeout) {
129 if (!(IsResolved || GetResolveSignal().Wait(timeout)))
95 if (!(IsFulfilled || GetFulfillSignal().Wait(timeout)))
130 throw new TimeoutException();
96 throw new TimeoutException();
131
97
132 switch (m_state) {
98 if (IsRejected)
133 case SUCCEEDED_STATE:
99 Rethrow();
134 return;
100 }
135 case CANCELLED_STATE:
101
136 throw new OperationCanceledException("The operation has been cancelled", m_error);
102 protected void Rethrow() {
137 case REJECTED_STATE:
103 Debug.Assert(m_error != null);
138 throw new TargetInvocationException(m_error);
104 if (m_error is OperationCanceledException)
139 default:
105 throw new OperationCanceledException("Operation cancelled", m_error);
140 throw new ApplicationException(String.Format("The promise state {0} is invalid", m_state));
106 else
141 }
107 throw new TargetInvocationException(m_error);
142 }
108 }
143 #endregion
109 #endregion
144
110
@@ -150,149 +116,55 namespace Implab {
150 // the promise is in the resolved state, just invoke the handler
116 // the promise is in the resolved state, just invoke the handler
151 SignalHandler(handler, m_state);
117 SignalHandler(handler, m_state);
152 } else {
118 } else {
153 var slot = Interlocked.Increment(ref m_handlersCount) - 1;
119 if (Interlocked.CompareExchange(ref m_handler, handler, null) != null) {
154
120 if (m_extraHandlers == null)
155 if (slot < RESERVED_HANDLERS_COUNT) {
121 // compare-exchange will fprotect from loosing already created queue
156
122 Interlocked.CompareExchange(ref m_extraHandlers, new SimpleAsyncQueue<THandler>(), null);
157 if (slot == 0) {
123 m_extraHandlers.Enqueue(handler);
158 m_handlers = new THandler[RESERVED_HANDLERS_COUNT];
124 }
159 } else {
160 while (m_handlers == null)
161 Thread.MemoryBarrier();
162 }
163
164 m_handlers[slot] = handler;
165
166 while (slot != Interlocked.CompareExchange(ref m_handlersCommited, slot + 1, slot)) {
167 }
168
125
169 if (m_state > 1) {
126 if (m_state > 1 && TryDequeueHandler(out handler))
170 do {
171 var hp = m_handlerPointer;
172 slot = hp + 1;
173 if (slot < m_handlersCommited) {
174 if (Interlocked.CompareExchange(ref m_handlerPointer, slot, hp) != hp)
175 continue;
176 SignalHandler(m_handlers[slot], m_state);
177 }
178 break;
179 } while(true);
180 }
181 } else {
182 if (slot == RESERVED_HANDLERS_COUNT) {
183 m_extraHandlers = new SimpleAsyncQueue<THandler>();
184 } else {
185 while (m_extraHandlers == null)
186 Thread.MemoryBarrier();
187 }
188
189 m_extraHandlers.Enqueue(handler);
190
191 if (m_state > 1 && m_extraHandlers.TryDequeue(out handler))
192 // if the promise have been resolved while we was adding the handler to the queue
127 // if the promise have been resolved while we was adding the handler to the queue
193 // we can't guarantee that someone is still processing it
128 // we can't guarantee that someone is still processing it
194 // therefore we need to fetch a handler from the queue and execute it
129 // therefore we need to fetch a handler from the queue and execute it
195 // note that fetched handler may be not the one that we have added
130 // note that fetched handler may be not the one that we have added
196 // even we can fetch no handlers at all :)
131 // even we can fetch no handlers at all :)
197 SignalHandler(handler, m_state);
132 SignalHandler(handler, m_state);
198 }
199 }
133 }
134
135 }
136
137 bool TryDequeueHandler(out THandler handler) {
138 handler = Interlocked.Exchange(ref m_handler, null);
139 if (handler != null)
140 return true;
141 return m_extraHandlers != null && m_extraHandlers.TryDequeue(out handler);
200 }
142 }
201
143
202 #endregion
144 #endregion
203
145
204 #region IPromise implementation
146 #region IPromise implementation
205
147
206 public bool IsResolved {
148 public bool IsFulfilled {
207 get {
149 get {
208 Thread.MemoryBarrier();
150 return m_state > TRANSITIONAL_STATE;
209 return m_state > 1;
210 }
151 }
211 }
152 }
212
153
213 public bool IsCancelled {
154 public bool IsRejected {
214 get {
155 get {
215 Thread.MemoryBarrier();
156 return m_state == REJECTED_STATE;
216 return m_state == CANCELLED_STATE;
217 }
157 }
218 }
158 }
219
159
220 #endregion
160 #endregion
221
161
222 public Exception Error {
162 public Exception RejectReason {
223 get {
163 get {
224 return m_error;
164 return m_error;
225 }
165 }
226 }
166 }
227
167
228 public bool CancelOperationIfRequested() {
229 if (IsCancellationRequested) {
230 CancelOperation(CancellationReason);
231 return true;
232 }
233 return false;
234 }
235
236 public virtual void CancelOperation(Exception reason) {
237 SetCancelled(reason);
238 }
239
240 public void CancellationRequested(Action<Exception> handler) {
241 Safe.ArgumentNotNull(handler, "handler");
242 if (IsCancellationRequested)
243 handler(CancellationReason);
244
245 if (m_cancelationHandlers == null)
246 Interlocked.CompareExchange(ref m_cancelationHandlers, new SimpleAsyncQueue<Action<Exception>>(), null);
247
248 m_cancelationHandlers.Enqueue(handler);
249
250 if (IsCancellationRequested && m_cancelationHandlers.TryDequeue(out handler))
251 // TryDeque implies MemoryBarrier()
252 handler(m_cancelationReason);
253 }
254
255 public bool IsCancellationRequested {
256 get {
257 do {
258 if (m_cancelRequest == CANCEL_NOT_REQUESTED)
259 return false;
260 if (m_cancelRequest == CANCEL_REQUESTED)
261 return true;
262 Thread.MemoryBarrier();
263 } while(true);
264 }
265 }
266
267 public Exception CancellationReason {
268 get {
269 do {
270 Thread.MemoryBarrier();
271 } while(m_cancelRequest == CANCEL_REQUESTING);
272
273 return m_cancelationReason;
274 }
275 }
276
277 #region ICancellable implementation
278
279 public void Cancel() {
280 Cancel(null);
281 }
282
283 public void Cancel(Exception reason) {
284 if (CANCEL_NOT_REQUESTED == Interlocked.CompareExchange(ref m_cancelRequest, CANCEL_REQUESTING, CANCEL_NOT_REQUESTED)) {
285 m_cancelationReason = reason;
286 m_cancelRequest = CANCEL_REQUESTED;
287 if (m_cancelationHandlers != null) {
288 Action<Exception> handler;
289 while (m_cancelationHandlers.TryDequeue(out handler))
290 handler(m_cancelationReason);
291 }
292 }
293 }
294
295 #endregion
296 }
168 }
297 }
169 }
298
170
@@ -3,28 +3,16 using Implab.Parallels;
3
3
4 namespace Implab {
4 namespace Implab {
5 public abstract class AbstractPromise : AbstractEvent<AbstractPromise.HandlerDescriptor>, IPromise {
5 public abstract class AbstractPromise : AbstractEvent<AbstractPromise.HandlerDescriptor>, IPromise {
6 public struct HandlerDescriptor {
6 public class HandlerDescriptor {
7 readonly Action m_handler;
7 readonly Action m_handler;
8 readonly Action<Exception> m_error;
8 readonly Action<Exception> m_error;
9 readonly Action<Exception> m_cancel;
9 public HandlerDescriptor(Action success, Action<Exception> error) {
10 readonly PromiseEventType m_mask;
11
12 public HandlerDescriptor(Action success, Action<Exception> error, Action<Exception> cancel) {
13 m_handler = success;
10 m_handler = success;
14 m_error = error;
11 m_error = error;
15 m_cancel = cancel;
16 m_mask = PromiseEventType.Success;
17 }
18
19 public HandlerDescriptor(Action handler, PromiseEventType mask) {
20 m_handler = handler;
21 m_error = null;
22 m_cancel = null;
23 m_mask = mask;
24 }
12 }
25
13
26 public void SignalSuccess() {
14 public void SignalSuccess() {
27 if ((m_mask & PromiseEventType.Success) != 0 && m_handler != null) {
15 if (m_handler != null) {
28 try {
16 try {
29 m_handler();
17 m_handler();
30 // Analysis disable once EmptyGeneralCatchClause
18 // Analysis disable once EmptyGeneralCatchClause
@@ -40,28 +28,6 namespace Implab {
40 // Analysis disable once EmptyGeneralCatchClause
28 // Analysis disable once EmptyGeneralCatchClause
41 } catch {
29 } catch {
42 }
30 }
43 } else if ((m_mask & PromiseEventType.Error ) != 0 && m_handler != null) {
44 try {
45 m_handler();
46 // Analysis disable once EmptyGeneralCatchClause
47 } catch {
48 }
49 }
50 }
51
52 public void SignalCancel(Exception reason) {
53 if (m_cancel != null) {
54 try {
55 m_cancel(reason);
56 // Analysis disable once EmptyGeneralCatchClause
57 } catch {
58 }
59 } else if ( (m_mask & PromiseEventType.Cancelled) != 0 && m_handler != null) {
60 try {
61 m_handler();
62 // Analysis disable once EmptyGeneralCatchClause
63 } catch {
64 }
65 }
31 }
66 }
32 }
67 }
33 }
@@ -75,48 +41,29 namespace Implab {
75 handler.SignalSuccess();
41 handler.SignalSuccess();
76 break;
42 break;
77 case REJECTED_STATE:
43 case REJECTED_STATE:
78 handler.SignalError(Error);
44 handler.SignalError(RejectReason);
79 break;
80 case CANCELLED_STATE:
81 handler.SignalCancel(CancellationReason);
82 break;
45 break;
83 default:
46 default:
84 throw new InvalidOperationException(String.Format("Invalid promise signal: {0}", signal));
47 throw new InvalidOperationException(String.Format("Invalid promise signal: {0}", signal));
85 }
48 }
86 }
49 }
87
50
88 protected override Signal GetResolveSignal() {
51 protected override Signal GetFulfillSignal() {
89 var signal = new Signal();
52 var signal = new Signal();
90 On(signal.Set, PromiseEventType.All);
53 On(signal.Set, e => signal.Set());
91 return signal;
54 return signal;
92 }
55 }
93
56
94 #endregion
57 #endregion
95
58
96 public Type PromiseType {
59 public Type ResultType {
97 get {
60 get {
98 return typeof(void);
61 return typeof(void);
99 }
62 }
100 }
63 }
101
64
102 public IPromise On(Action success, Action<Exception> error, Action<Exception> cancel) {
65 public void On(Action success, Action<Exception> error) {
103 AddHandler(new HandlerDescriptor(success, error, cancel));
66 AddHandler(new HandlerDescriptor(success, error));
104 return this;
105 }
106
107 public IPromise On(Action success, Action<Exception> error) {
108 AddHandler(new HandlerDescriptor(success, error, null));
109 return this;
110 }
111
112 public IPromise On(Action success) {
113 AddHandler(new HandlerDescriptor(success, null, null));
114 return this;
115 }
116
117 public IPromise On(Action handler, PromiseEventType events) {
118 AddHandler(new HandlerDescriptor(handler,events));
119 return this;
120 }
67 }
121
68
122 public IPromise<T> Cast<T>() {
69 public IPromise<T> Cast<T>() {
@@ -84,7 +84,7 namespace Implab {
84 }
84 }
85 }
85 }
86
86
87 public Type PromiseType {
87 public Type ResultType {
88 get {
88 get {
89 return typeof(T);
89 return typeof(T);
90 }
90 }
@@ -167,7 +167,7 namespace Implab {
167
167
168 #region implemented abstract members of AbstractPromise
168 #region implemented abstract members of AbstractPromise
169
169
170 protected override Signal GetResolveSignal() {
170 protected override Signal GetFulfillSignal() {
171 var signal = new Signal();
171 var signal = new Signal();
172 AddHandler(new HandlerDescriptor(signal.Set, PromiseEventType.All));
172 AddHandler(new HandlerDescriptor(signal.Set, PromiseEventType.All));
173 return signal;
173 return signal;
@@ -179,7 +179,7 namespace Implab {
179 handler.SignalSuccess(m_result);
179 handler.SignalSuccess(m_result);
180 break;
180 break;
181 case REJECTED_STATE:
181 case REJECTED_STATE:
182 handler.SignalError(Error);
182 handler.SignalError(RejectReason);
183 break;
183 break;
184 case CANCELLED_STATE:
184 case CANCELLED_STATE:
185 handler.SignalCancel(CancellationReason);
185 handler.SignalCancel(CancellationReason);
@@ -53,20 +53,20 namespace Implab {
53 }
53 }
54
54
55 public void Join() {
55 public void Join() {
56 throw new TargetInvocationException(Error);
56 throw new TargetInvocationException(RejectReason);
57 }
57 }
58
58
59 public void Join(int timeout) {
59 public void Join(int timeout) {
60 throw new TargetInvocationException(Error);
60 throw new TargetInvocationException(RejectReason);
61 }
61 }
62
62
63 public virtual Type PromiseType {
63 public virtual Type ResultType {
64 get {
64 get {
65 return typeof(void);
65 return typeof(void);
66 }
66 }
67 }
67 }
68
68
69 public bool IsResolved {
69 public bool IsFulfilled {
70 get {
70 get {
71 return true;
71 return true;
72 }
72 }
@@ -78,7 +78,7 namespace Implab {
78 }
78 }
79 }
79 }
80
80
81 public Exception Error {
81 public Exception RejectReason {
82 get {
82 get {
83 return m_error;
83 return m_error;
84 }
84 }
@@ -9,7 +9,7 namespace Implab {
9 public IPromise<T> On(Action<T> success, Action<Exception> error, Action<Exception> cancel) {
9 public IPromise<T> On(Action<T> success, Action<Exception> error, Action<Exception> cancel) {
10 if (error != null) {
10 if (error != null) {
11 try {
11 try {
12 error(Error);
12 error(RejectReason);
13 // Analysis disable once EmptyGeneralCatchClause
13 // Analysis disable once EmptyGeneralCatchClause
14 } catch {
14 } catch {
15 }
15 }
@@ -20,7 +20,7 namespace Implab {
20 public IPromise<T> On(Action<T> success, Action<Exception> error) {
20 public IPromise<T> On(Action<T> success, Action<Exception> error) {
21 if (error != null) {
21 if (error != null) {
22 try {
22 try {
23 error(Error);
23 error(RejectReason);
24 // Analysis disable once EmptyGeneralCatchClause
24 // Analysis disable once EmptyGeneralCatchClause
25 } catch {
25 } catch {
26 }
26 }
@@ -33,11 +33,11 namespace Implab {
33 }
33 }
34
34
35 T IPromise<T>.Join() {
35 T IPromise<T>.Join() {
36 throw new TargetInvocationException(Error);
36 throw new TargetInvocationException(RejectReason);
37 }
37 }
38
38
39 T IPromise<T>.Join(int timeout) {
39 T IPromise<T>.Join(int timeout) {
40 throw new TargetInvocationException(Error);
40 throw new TargetInvocationException(RejectReason);
41 }
41 }
42
42
43
43
@@ -9,42 +9,29 namespace Implab {
9 /// <summary>
9 /// <summary>
10 /// Тип результата, получаемого через данное обещание.
10 /// Тип результата, получаемого через данное обещание.
11 /// </summary>
11 /// </summary>
12 Type PromiseType { get; }
12 Type ResultType { get; }
13
13
14 /// <summary>
14 /// <summary>
15 /// Обещание является выполненым, либо успешно, либо с ошибкой, либо отменено.
15 /// Обещание является выполненым, либо успешно, либо с ошибкой, либо отменено.
16 /// </summary>
16 /// </summary>
17 bool IsResolved { get; }
17 bool IsFulfilled { get; }
18
18
19 /// <summary>
19 bool IsRejected { get; }
20 /// Обещание было отменено.
20
21 /// </summary>
21 bool IsResolved { get; }
22 bool IsCancelled { get; }
23
22
24 /// <summary>
23 /// <summary>
25 /// Исключение возникшее в результате выполнения обещания, либо причина отмены.
24 /// Исключение возникшее в результате выполнения обещания, либо причина отмены.
26 /// </summary>
25 /// </summary>
27 Exception Error { get; }
26 Exception RejectReason { get; }
28
27
29 /// <summary>
28 /// <summary>
30 /// Adds specified listeners to the current promise.
29 /// Adds specified listeners to the current promise.
31 /// </summary>
30 /// </summary>
32 /// <param name="success">The handler called on the successful promise completion.</param>
31 /// <param name="success">The handler called on the successful promise completion.</param>
33 /// <param name="error">The handler is called if an error while completing the promise occurred.</param>
32 /// <param name="error">The handler is called if an error while completing the promise occurred.</param>
34 /// <param name="cancel">The handler is called in case of promise cancellation.</param>
35 /// <returns>The current promise.</returns>
33 /// <returns>The current promise.</returns>
36 IPromise On(Action success, Action<Exception> error, Action<Exception> cancel);
34 void On(Action success, Action<Exception> error);
37 IPromise On(Action success, Action<Exception> error);
38 IPromise On(Action success);
39
40 /// <summary>
41 /// Adds specified listeners to the current promise.
42 /// </summary>
43 /// <param name="handler">The handler called on the specified events.</param>
44 /// <param name = "events">The combination of flags denoting the events for which the
45 /// handler shoud be called.</param>
46 /// <returns>The current promise.</returns>
47 IPromise On(Action handler, PromiseEventType events);
48
35
49 /// <summary>
36 /// <summary>
50 /// Преобразует результат обещания к заданному типу и возвращает новое обещание.
37 /// Преобразует результат обещания к заданному типу и возвращает новое обещание.
@@ -3,23 +3,10
3 namespace Implab {
3 namespace Implab {
4 public interface IPromise<out T> : IPromise {
4 public interface IPromise<out T> : IPromise {
5
5
6 IPromise<T> On(Action<T> success, Action<Exception> error, Action<Exception> cancel);
6 void On(Action<T> success, Action<Exception> error);
7
8 IPromise<T> On(Action<T> success, Action<Exception> error);
9
10 IPromise<T> On(Action<T> success);
11
7
12 new T Join();
8 new T Join();
13
9
14 new T Join(int timeout);
10 new T Join(int timeout);
15
16 new IPromise<T> On(Action success, Action<Exception> error, Action<Exception> cancel);
17
18 new IPromise<T> On(Action success, Action<Exception> error);
19
20 new IPromise<T> On(Action success);
21
22 new IPromise<T> On(Action handler, PromiseEventType events);
23
24 }
11 }
25 }
12 }
@@ -164,7 +164,7 namespace Implab.Parallels {
164 // Analysis disable AccessToDisposedClosure
164 // Analysis disable AccessToDisposedClosure
165 AsyncPool.RunThread<int>(() => {
165 AsyncPool.RunThread<int>(() => {
166 for (int i = 0; i < source.Length; i++) {
166 for (int i = 0; i < source.Length; i++) {
167 if(promise.IsResolved)
167 if(promise.IsFulfilled)
168 break; // stop processing in case of error or cancellation
168 break; // stop processing in case of error or cancellation
169 var idx = i;
169 var idx = i;
170
170
@@ -15,12 +15,12 namespace Implab.Parallels {
15
15
16 // the reader and the writer are mainteined completely independent,
16 // the reader and the writer are mainteined completely independent,
17 // the reader can read next item when m_first.next is not null
17 // the reader can read next item when m_first.next is not null
18 // the writer creates the a new node, moves m_last to this node and
18 // the writer creates a new node, moves m_last to this node and
19 // only after that restores the reference from the previous node
19 // only after that restores the reference from the previous node
20 // making available the reader to read the new node.
20 // making the reader be able to read the new node.
21
21
22 Node m_first; // position on the node which is already read
22 volatile Node m_first; // position on the node which is already read
23 Node m_last; // position on the node which is already written
23 volatile Node m_last; // position on the node which is already written
24
24
25 public SimpleAsyncQueue() {
25 public SimpleAsyncQueue() {
26 m_first = m_last = new Node(default(T));
26 m_first = m_last = new Node(default(T));
@@ -35,29 +35,38 namespace Implab.Parallels {
35
35
36 // release-fence
36 // release-fence
37 last.next = next;
37 last.next = next;
38
38
39 }
39 }
40
40
41 public bool TryDequeue(out T value) {
41 public bool TryDequeue(out T value) {
42 Node first;
42 Node first = m_first; ;
43 Node next;
43 Node next = first.next; ;
44
45 if (next == null) {
46 value = default(T);
47 return false;
48 }
49
50 var first2 = Interlocked.CompareExchange(ref m_first, next, first);
51
52 if (first != first2) {
53 // head is updated by someone else
44
54
45 Thread.MemoryBarrier(); // ensure m_first is fresh
55 SpinWait spin = new SpinWait();
46 SpinWait spin = new SpinWait();
56 do {
47 do {
57 first = first2;
48 first = m_first;
58 next = first.next;
49 // aquire-fence
59 if (next == null) {
50 next = first.next;
60 value = default(T);
51 if (next == null) {
61 return false;
52 value = default(T);
62 }
53 return false;
63
54 }
64 first2 = Interlocked.CompareExchange(ref m_first, next, first);
55
65 if (first == first2)
56 if (first == Interlocked.CompareExchange(ref m_first, next, first))
66 break;
57 // head succesfully updated
67 spin.SpinOnce();
58 break;
68 } while (true);
59 spin.SpinOnce();
69 }
60 } while (true);
61
70
62 value = next.value;
71 value = next.value;
63 return true;
72 return true;
@@ -20,7 +20,7 namespace Implab {
20
20
21 public bool IsCompleted {
21 public bool IsCompleted {
22 get {
22 get {
23 return m_promise.IsResolved;
23 return m_promise.IsFulfilled;
24 }
24 }
25 }
25 }
26 }
26 }
@@ -20,7 +20,7 namespace Implab {
20
20
21 public bool IsCompleted {
21 public bool IsCompleted {
22 get {
22 get {
23 return m_promise.IsResolved;
23 return m_promise.IsFulfilled;
24 }
24 }
25 }
25 }
26 }
26 }
@@ -58,13 +58,13 namespace Implab {
58 public void Join(int timeout) {
58 public void Join(int timeout) {
59 }
59 }
60
60
61 public Type PromiseType {
61 public Type ResultType {
62 get {
62 get {
63 return typeof(void);
63 return typeof(void);
64 }
64 }
65 }
65 }
66
66
67 public bool IsResolved {
67 public bool IsFulfilled {
68 get {
68 get {
69 return true;
69 return true;
70 }
70 }
@@ -76,7 +76,7 namespace Implab {
76 }
76 }
77 }
77 }
78
78
79 public Exception Error {
79 public Exception RejectReason {
80 get {
80 get {
81 return null;
81 return null;
82 }
82 }
@@ -119,13 +119,13 namespace Implab {
119 void IPromise.Join(int timeout) {
119 void IPromise.Join(int timeout) {
120 }
120 }
121
121
122 public Type PromiseType {
122 public Type ResultType {
123 get {
123 get {
124 return typeof(T);
124 return typeof(T);
125 }
125 }
126 }
126 }
127
127
128 public bool IsResolved {
128 public bool IsFulfilled {
129 get {
129 get {
130 return true;
130 return true;
131 }
131 }
@@ -137,7 +137,7 namespace Implab {
137 }
137 }
138 }
138 }
139
139
140 public Exception Error {
140 public Exception RejectReason {
141 get {
141 get {
142 return null;
142 return null;
143 }
143 }
@@ -1,5 +1,6
1 <?xml version="1.0" encoding="utf-8"?>
1 <?xml version="1.0" encoding="utf-8"?>
2 <repositories>
2 <repositories>
3 <repository path="../Implab.Test/Implab.Format.Test/packages.config" />
3 <repository path="../Implab.Test/Implab.Format.Test/packages.config" />
4 <repository path="../Implab.Test/packages.config" />
4 <repository path="../MonoPlay/packages.config" />
5 <repository path="../MonoPlay/packages.config" />
5 </repositories> No newline at end of file
6 </repositories>
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