Last active
September 6, 2015 02:12
-
-
Save noseratio/0ac63d2d21428f6cd7d6 to your computer and use it in GitHub Desktop.
AlwaysAsyncAwaiter - http://stackoverflow.com/questions/32412426/unexpected-stack-overflow-despite-yielding
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
// 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