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

File last commit:

r244:eee3e49dd1ff v3
r245:b904e0a3ba72 v3
Show More
AbstractEvent.cs
141 lines | 4.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
r243 /// <summary>
/// Abstract class for creation of custom one-shot thread safe events.
/// </summary>
/// <remarks>
/// <para>
/// An event is something that should happen in the future and the
/// triggering of the event causes execution of some pending actions
/// which are formely event handlers. One-shot events occur only once
/// and any handler added after the event is triggered should run
/// without a delay.
/// </para>
/// <para>
/// The lifecycle of the one-shot event is tipically consists of following
/// phases.
/// <list>
/// <description>Pending state. This is the initial state of the event. Any
/// handler added to the event will be queued for the future execution.
/// </description>
/// <description>Transitional state. This is intermediate state between pending
/// and fulfilled states, during this state internal initialization and storing
/// of the result occurs.
/// </description>
/// <description>Fulfilled state. The event contains the result, all queued
/// handlers are signalled to run and newly added handlers are executed
/// immediatelly.
/// </description>
/// </list>
/// </para>
/// </remarks>
cin
Working on promises
r242 public abstract class AbstractEvent<THandler> where THandler : class {
cin
working on promises
r244 const int PendingState = 0;
cin
Working on promises
r242
cin
working on promises
r244 const int TransitionalState = 1;
cin
working on promises
r243
cin
working on promises
r244 const int ResolvedState = 2;
cin
DRAFT: refactoring
r144
cin
Working on promises
r242 volatile int m_state;
cin
DRAFT: refactoring
r144
cin
Working on promises
r242 THandler m_handler;
cin
Improved AsyncQueue...
r233 SimpleAsyncQueue<THandler> m_extraHandlers;
cin
DRAFT: refactoring
r144
cin
working on promises
r244 public bool IsResolved {
cin
working on promises
r243 get {
cin
working on promises
r244 return m_state > TransitionalState;
cin
working on promises
r243 }
}
cin
DRAFT: refactoring
r144 #region state managment
cin
Working on promises
r242 protected bool BeginTransit() {
cin
working on promises
r244 return PendingState == Interlocked.CompareExchange(ref m_state, TransitionalState, PendingState);
cin
DRAFT: refactoring
r144 }
cin
working on promises
r243 protected void CompleteTransit() {
cin
Working on promises
r242 #if DEBUG
cin
working on promises
r244 if (TransitionalState != Interlocked.CompareExchange(ref m_state, ResolvedState, TransitionalState))
cin
DRAFT: refactoring
r144 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() {
cin
working on promises
r244 if (m_state == TransitionalState) {
cin
Working on promises
r242 SpinWait spin;
do {
spin.SpinOnce();
cin
working on promises
r244 } while (m_state == TransitionalState);
cin
DRAFT: refactoring
r144 }
}
cin
working on promises
r243 protected abstract void SignalHandler(THandler handler);
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))
cin
working on promises
r243 SignalHandler(handler);
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
r244 if (!(IsResolved || GetFulfillSignal().Wait(timeout)))
cin
fixed timeout handling in promises
r148 throw new TimeoutException();
cin
Working on promises
r242 }
cin
working on promises
r243
cin
DRAFT: refactoring
r144 #endregion
#region handlers managment
protected void AddHandler(THandler handler) {
cin
working on promises
r244 if (IsResolved) {
cin
DRAFT: refactoring
r144 // the promise is in the resolved state, just invoke the handler
cin
working on promises
r243 SignalHandler(handler);
cin
DRAFT: refactoring
r144 } else {
cin
working on promises
r243 EnqueueHandler(handler);
cin
DRAFT: refactoring
r144
cin
working on promises
r244 if (IsResolved && 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
r243 SignalHandler(handler);
cin
DRAFT: refactoring
r144 }
cin
Working on promises
r242
}
cin
working on promises
r243 void EnqueueHandler(THandler handler) {
if (Interlocked.CompareExchange(ref m_handler, handler, null) != null) {
if (m_extraHandlers == null)
// compare-exchange will protect from loosing already created queue
Interlocked.CompareExchange(ref m_extraHandlers, new SimpleAsyncQueue<THandler>(), null);
m_extraHandlers.Enqueue(handler);
}
}
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
}
}