Skip to content

Instantly share code, notes, and snippets.

@noseratio
Last active September 6, 2015 02:12
Show Gist options
  • Save noseratio/0ac63d2d21428f6cd7d6 to your computer and use it in GitHub Desktop.
Save noseratio/0ac63d2d21428f6cd7d6 to your computer and use it in GitHub Desktop.
// http://stackoverflow.com/questions/32412426/unexpected-stack-overflow-despite-yielding
public static class TaskExt
{
public static AlwaysAsyncAwaiter<T> AlwaysAsync<T>(this Task<T> @this) { return new AlwaysAsyncAwaiter<T>(@this); }
public struct AlwaysAsyncAwaiter<T> : System.Runtime.CompilerServices.ICriticalNotifyCompletion
{
readonly Task<T> _task;
public AlwaysAsyncAwaiter(Task<T> task)
{
_task = task;
}
public AlwaysAsyncAwaiter<T> GetAwaiter() { return this; }
public bool IsCompleted { get { return false; } }
public T GetResult() { return _task.GetAwaiter().GetResult(); }
public void UnsafeOnCompleted(Action continuation)
{
// optimization (it has a race condition which we address below)
if (_task.IsCompleted)
{
ThreadPool.UnsafeQueueUserWorkItem(_ => continuation(), null);
return;
}
// task can still get completed before ContinueWith returns
var locker = new Object();
lock (locker)
{
var executedSynchronously = true;
try
{
using (ExecutionContext.SuppressFlow())
{
_task.ContinueWith(
_ =>
{
lock (locker)
{
if (executedSynchronously)
{
ThreadPool.UnsafeQueueUserWorkItem(__ => continuation(), null);
return;
}
}
continuation();
},
CancellationToken.None,
TaskContinuationOptions.ExecuteSynchronously,
TaskScheduler.Default);
}
}
finally
{
executedSynchronously = false;
}
}
//// simulate a race condition
//Thread.Sleep(100);
//Console.WriteLine(new { where = "inside", Environment.CurrentManagedThreadId });
}
public void OnCompleted(Action continuation)
{
throw new NotImplementedException();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment