Created
May 5, 2011 16:42
-
-
Save duarten/957391 to your computer and use it in GitHub Desktop.
A simple Actor implementation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class Actor<TState> | |
{ | |
volatile int executing; | |
readonly ConcurrentQueue<Func<TState, Task>> funcs = new ConcurrentQueue<Func<TState, Task>>(); | |
public TState State { get; set; } | |
public void Act(Func<TState, Task> func) | |
{ | |
if (TryAcquire()) | |
{ | |
Task.Factory.StartNew(() => ExecuteAction(func)); | |
return; | |
} | |
funcs.Enqueue(func); | |
if (TryAcquire()) | |
TryExecuteAction(); | |
} | |
public event EventHandler<UnhandledExceptionEventArgs> OnError; | |
private void ExecuteAction(Func<TState, Task> func) | |
{ | |
func(State).ContinueWith(x => | |
{ | |
if (x.Exception != null) | |
{ | |
InvokeOnError(new UnhandledExceptionEventArgs(x.Exception, false)); | |
return; | |
} | |
TryExecuteAction(); | |
}); | |
} | |
private void TryExecuteAction() | |
{ | |
do | |
{ | |
Func<TState, Task> func; | |
if (funcs.TryDequeue(out func)) | |
{ | |
ExecuteAction(func); | |
return; | |
} | |
Interlocked.Exchange(ref executing, 0); | |
} while (funcs.IsEmpty == false && TryAcquire()); | |
} | |
private bool TryAcquire() | |
{ | |
return executing == 0 && Interlocked.Exchange(ref executing, 1) == 0; | |
} | |
private void InvokeOnError(UnhandledExceptionEventArgs e) | |
{ | |
var handler = OnError; | |
if (handler == null) | |
throw new InvalidOperationException("An error was raised for an actor with no error handling capabilities"); | |
handler(this, e); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment