Skip to content

Instantly share code, notes, and snippets.

@duarten
Created May 5, 2011 16:42
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save duarten/957391 to your computer and use it in GitHub Desktop.
Save duarten/957391 to your computer and use it in GitHub Desktop.
A simple Actor implementation
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