##// END OF EJS Templates
Working on promises
Working on promises

File last commit:

r242:cbe10ac0731e v3
r242:cbe10ac0731e v3
Show More
AbstractEvent.cs
170 lines | 5.7 KiB | text/x-csharp | CSharpLexer
cin
DRAFT: refactoring
r144 using System;
using Implab.Parallels;
using System.Threading;
using System.Reflection;
cin
Working on promises
r242 using System.Diagnostics;
cin
DRAFT: refactoring
r144
namespace Implab {
cin
Working on promises
r242 public abstract class AbstractEvent<THandler> where THandler : class {
cin
DRAFT: refactoring
r144
cin
Working on promises
r242 const int PENDING_SATE = 0;
protected const int TRANSITIONAL_STATE = 1;
cin
Promises: SignalXXX methods merged into SignalHandler method....
r156 protected const int SUCCEEDED_STATE = 2;
protected const int REJECTED_STATE = 3;
cin
DRAFT: refactoring
r144
cin
Working on promises
r242 volatile int m_state;
cin
DRAFT: refactoring
r144 Exception m_error;
cin
Working on promises
r242 THandler m_handler;
cin
Improved AsyncQueue...
r233 SimpleAsyncQueue<THandler> m_extraHandlers;
cin
DRAFT: refactoring
r144
#region state managment
cin
Working on promises
r242 protected bool BeginTransit() {
return PENDING_SATE == Interlocked.CompareExchange(ref m_state, TRANSITIONAL_STATE, PENDING_SATE);
cin
DRAFT: refactoring
r144 }
cin
Working on promises
r242 protected void CompleteTransit(int state) {
#if DEBUG
cin
DRAFT: refactoring
r144 if (TRANSITIONAL_STATE != Interlocked.CompareExchange(ref m_state, state, TRANSITIONAL_STATE))
throw new InvalidOperationException("Can't complete transition when the object isn't in the transitional state");
cin
Working on promises
r242 #else
m_state = state;
#endif
Signal();
cin
DRAFT: refactoring
r144 }
cin
Working on promises
r242 protected void WaitTransition() {
if (m_state == TRANSITIONAL_STATE) {
SpinWait spin;
do {
spin.SpinOnce();
} while (m_state == TRANSITIONAL_STATE);
cin
DRAFT: refactoring
r144 }
}
protected bool BeginSetResult() {
if (!BeginTransit()) {
WaitTransition();
return false;
}
return true;
}
protected void EndSetResult() {
CompleteTransit(SUCCEEDED_STATE);
}
/// <summary>
/// Выполняет обещание, сообщая об ошибке
/// </summary>
/// <remarks>
/// Поскольку обещание должно работать в многопточной среде, при его выполнении сразу несколько потоков
/// могу вернуть ошибку, при этом только первая будет использована в качестве результата, остальные
/// будут проигнорированы.
/// </remarks>
/// <param name="error">Исключение возникшее при выполнении операции</param>
/// <exception cref="InvalidOperationException">Данное обещание уже выполнено</exception>
protected void SetError(Exception error) {
if (BeginTransit()) {
cin
working on cancelation and error handling
r186 m_error = error;
CompleteTransit(REJECTED_STATE);
cin
DRAFT: refactoring
r144 } else {
WaitTransition();
cin
working on cancelation and error handling
r186 if (m_state == SUCCEEDED_STATE)
cin
DRAFT: refactoring
r144 throw new InvalidOperationException("The promise is already resolved");
}
}
cin
Promises: SignalXXX methods merged into SignalHandler method....
r156 protected abstract void SignalHandler(THandler handler, int signal);
cin
DRAFT: refactoring
r144
cin
Promises: SignalXXX methods merged into SignalHandler method....
r156 void Signal() {
cin
Working on promises
r242 THandler handler;
while (TryDequeueHandler(out handler))
SignalHandler(handler, m_state);
cin
DRAFT: refactoring
r144 }
#endregion
cin
Working on promises
r242 protected abstract Signal GetFulfillSignal();
cin
DRAFT: refactoring
r144
#region synchronization traits
protected void WaitResult(int timeout) {
cin
Working on promises
r242 if (!(IsFulfilled || GetFulfillSignal().Wait(timeout)))
cin
fixed timeout handling in promises
r148 throw new TimeoutException();
cin
DRAFT: refactoring
r144
cin
Working on promises
r242 if (IsRejected)
Rethrow();
}
protected void Rethrow() {
Debug.Assert(m_error != null);
if (m_error is OperationCanceledException)
throw new OperationCanceledException("Operation cancelled", m_error);
else
throw new TargetInvocationException(m_error);
cin
DRAFT: refactoring
r144 }
#endregion
#region handlers managment
protected void AddHandler(THandler handler) {
if (m_state > 1) {
// the promise is in the resolved state, just invoke the handler
cin
Promises: SignalXXX methods merged into SignalHandler method....
r156 SignalHandler(handler, m_state);
cin
DRAFT: refactoring
r144 } else {
cin
Working on promises
r242 if (Interlocked.CompareExchange(ref m_handler, handler, null) != null) {
if (m_extraHandlers == null)
// compare-exchange will fprotect from loosing already created queue
Interlocked.CompareExchange(ref m_extraHandlers, new SimpleAsyncQueue<THandler>(), null);
m_extraHandlers.Enqueue(handler);
}
cin
DRAFT: refactoring
r144
cin
Working on promises
r242 if (m_state > 1 && TryDequeueHandler(out handler))
cin
DRAFT: refactoring
r144 // if the promise have been resolved while we was adding the handler to the queue
// we can't guarantee that someone is still processing it
// therefore we need to fetch a handler from the queue and execute it
// note that fetched handler may be not the one that we have added
// even we can fetch no handlers at all :)
cin
Working on promises
r242 SignalHandler(handler, m_state);
cin
DRAFT: refactoring
r144 }
cin
Working on promises
r242
}
bool TryDequeueHandler(out THandler handler) {
handler = Interlocked.Exchange(ref m_handler, null);
if (handler != null)
return true;
return m_extraHandlers != null && m_extraHandlers.TryDequeue(out handler);
cin
DRAFT: refactoring
r144 }
#endregion
#region IPromise implementation
cin
Working on promises
r242 public bool IsFulfilled {
cin
DRAFT: refactoring
r144 get {
cin
Working on promises
r242 return m_state > TRANSITIONAL_STATE;
cin
DRAFT: refactoring
r144 }
}
cin
Working on promises
r242 public bool IsRejected {
cin
DRAFT: refactoring
r144 get {
cin
Working on promises
r242 return m_state == REJECTED_STATE;
cin
DRAFT: refactoring
r144 }
}
#endregion
cin
Working on promises
r242 public Exception RejectReason {
cin
DRAFT: refactoring
r144 get {
return m_error;
}
}
}
}