diff --git a/Implab/IPromise.cs b/Implab/IPromise.cs
--- a/Implab/IPromise.cs
+++ b/Implab/IPromise.cs
@@ -26,7 +26,7 @@ namespace Implab
///
/// Tries to cancel the promise or the complete chain.
///
- /// Try to cancel the parent promise is it has the only one child
+ /// Try to cancel the whole promise chain, the parent promise will be cancelled only if it has only one promise
///
bool Cancel(bool dependencies);
}
diff --git a/Implab/Promise.cs b/Implab/Promise.cs
--- a/Implab/Promise.cs
+++ b/Implab/Promise.cs
@@ -48,28 +48,32 @@ namespace Implab {
/// только инициатор обещания иначе могут возникнуть противоречия.
///
///
- public class Promise: IPromise {
+ public class Promise : IPromise {
struct ResultHandlerInfo {
public ResultHandler resultHandler;
public ErrorHandler errorHandler;
- public Action cancelHandler;
}
- LinkedList m_handlersChain = new LinkedList();
+ IPromise m_parent;
+
+ LinkedList m_resultHandlers = new LinkedList();
+ LinkedList m_cancelHandlers = new LinkedList();
+
+ object m_lock = new Object();
+ bool m_cancellable;
+
PromiseState m_state;
- bool m_cancellable;
T m_result;
Exception m_error;
- IPromise m_parent;
+
int m_childrenCount;
public Promise() {
m_cancellable = true;
}
- public Promise(IPromise parent, bool cancellable)
- {
+ public Promise(IPromise parent, bool cancellable) {
m_cancellable = cancellable;
m_parent = parent;
}
@@ -97,9 +101,14 @@ namespace Implab {
m_state = PromiseState.Resolved;
}
- ResultHandlerInfo handler;
+ // state has been changed to rejected new handlers can't be added
+
+ foreach (var handler in m_resultHandlers)
+ InvokeHandler(handler);
+
+ /* ResultHandlerInfo handler;
while (FetchNextHandler(out handler))
- InvokeHandler(handler);
+ InvokeHandler(handler); */
}
///
@@ -117,9 +126,14 @@ namespace Implab {
m_state = PromiseState.Rejected;
}
- ResultHandlerInfo handler;
+ // state has been changed to rejected new handlers can't be added
+
+ foreach (var handler in m_resultHandlers)
+ InvokeHandler(handler);
+
+ /*ResultHandlerInfo handler;
while (FetchNextHandler(out handler))
- InvokeHandler(handler);
+ InvokeHandler(handler);*/
}
///
@@ -127,19 +141,7 @@ namespace Implab {
///
/// true Операция была отменена, обработчики не будут вызваны.false отмена не возможна, поскольку обещание уже выполнено и обработчики отработали.
public bool Cancel() {
- lock (this) {
- if (m_state == PromiseState.Unresolved && m_cancellable)
- {
- m_state = PromiseState.Cancelled;
- EventHandler temp = Cancelled;
-
- if (temp != null)
- temp(this, new EventArgs());
-
- return true;
- } else
- return false;
- }
+ return Cancel(true);
}
///
@@ -353,9 +355,9 @@ namespace Implab {
lock (this) {
Debug.Assert(m_state != PromiseState.Unresolved);
- if (m_handlersChain.Count > 0) {
- handler = m_handlersChain.First.Value;
- m_handlersChain.RemoveFirst();
+ if (m_resultHandlers.Count > 0) {
+ handler = m_resultHandlers.First.Value;
+ m_resultHandlers.RemoveFirst();
return true;
} else {
return false;
@@ -368,7 +370,7 @@ namespace Implab {
lock (this) {
if (m_state == PromiseState.Unresolved)
- m_handlersChain.AddLast(handler);
+ m_resultHandlers.AddLast(handler);
else
invokeRequired = true;
}
@@ -395,5 +397,47 @@ namespace Implab {
}
+
+ public bool IsExclusive {
+ get {
+ lock (m_lock) {
+ return m_childrenCount <= 1;
+ }
+ }
+ }
+
+ public PromiseState State {
+ get {
+ lock (m_lock) {
+ return m_state;
+ }
+ }
+ }
+
+ public bool Cancel(bool dependencies) {
+ bool result;
+
+ lock (m_lock) {
+ if (m_state == PromiseState.Unresolved) {
+ m_state = PromiseState.Cancelled;
+ result = true;
+ } else {
+ result = false;
+ }
+ }
+
+ if (dependencies && m_parent != null && m_parent.IsExclusive) {
+ // TODO syncronize IsExclusive, AddHandler, Cancel (maybe CancelExclusive)
+ m_parent.Cancel(true);
+ }
+
+ if (result) {
+ // state has been changed to cancelled, new handlers can't be added
+ foreach (var handler in m_cancelHandlers)
+ handler();
+ }
+
+ return result;
+ }
}
}