using System.Threading.Tasks;
using System.Runtime.CompilerServices;
public static async Task Main()
Message message = new Message();
ScheduleMessageCompletion();
Print("Before await message");
Print("After await message");
async void ScheduleMessageCompletion()
public class Message : INotifyCompletion
private static readonly Action _completedSentinel = new(() => { });
private Action _continuation;
public Message GetAwaiter() { return this; }
=> ReferenceEquals(Volatile.Read(ref _continuation), _completedSentinel);
public void OnCompleted(Action continuation)
Action original = Interlocked.CompareExchange(ref _continuation,
if (original is null) return;
if (ReferenceEquals(original, _completedSentinel))
throw new InvalidOperationException("Double await");
public void GetResult() { }
public void SetCompleted()
Action continuation = Interlocked.Exchange(ref _continuation,
if (continuation is null) return;
ThreadPool.QueueUserWorkItem(state => ((Action)state).Invoke(), continuation);
private static void Print(object value)
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff} [{Thread.CurrentThread.ManagedThreadId}] > {value}");