class Program { static void Main() { Go(); Console.ReadKey(); } public static async Task Go() { #if DEBUG //使用会影响性能和内存,所以只在调试生成中启用它 TaskLogger.LogLevel = TaskLogger.TaskLogLevel.Pending; #endif //初始化为3个任务:为测试TaskLogger,我们显示控制其持续时间 var tasks = new List<Task> { Task.Delay(2000).Log("2s op"), Task.Delay(5000).Log("5s op"), Task.Delay(6000).Log("6s op") }; try { //等待全部任务,但在 3秒后取消:只有一个任务能按时完成 await Task.WhenAll(tasks).WithCancellation(new CancellationTokenSource(3000).Token); } catch (Exception) { //查询logger哪些任务尚未完成,按照从等待时间最长到最短的顺序排序 foreach (var op in TaskLogger.GetLogEntries().OrderBy(tle => tle.LogTime)) Console.WriteLine(op); } } } public static class TaskLogger { public enum TaskLogLevel { None, Pending } public static TaskLogLevel LogLevel { get; set; } private static readonly ConcurrentDictionary<Task, TaskLogEntry> s_log = new ConcurrentDictionary<Task, TaskLogEntry>(); public static IEnumerable<TaskLogEntry> GetLogEntries() { return s_log.Values; } public sealed class TaskLogEntry { public Task Task { get; internal set; } public string Tag { get; internal set; } public DateTime LogTime { get; internal set; } public string CallerMemberName { get; internal set; } public string CallerFilePath { get; internal set; } public int CallerLineNumber { get; internal set; } public override string ToString() { return string.Format("LogTime={0},Tag={1},Member={2},File={3}({4})", LogTime, Tag ?? "(None)", CallerMemberName, CallerFilePath, CallerLineNumber); } } public static Task<TResult> Log<TResult>(this Task<TResult> task, string tag = null, [CallerMemberName] string callerMemberName = null, [CallerFilePath] string callerFilePath = null, [CallerLineNumber] int callerLineNumber = -1) { return (Task<TResult>)Log((Task)task, tag, callerMemberName, callerFilePath, callerLineNumber); } public static Task Log(this Task task, string tag = null, [CallerMemberName] string callerMemberName = null, [CallerFilePath] string callerFilePath = null, [CallerLineNumber] int callerLineNumber = -1) { if (LogLevel == TaskLogLevel.None) return task; var logEntry = new TaskLogEntry { Task = task, LogTime = DateTime.Now, Tag = tag, CallerMemberName = callerMemberName, CallerFilePath = callerFilePath, CallerLineNumber = callerLineNumber }; s_log[task] = logEntry; task.ContinueWith(t => { TaskLogEntry entry; s_log.TryRemove(t, out entry); }, TaskContinuationOptions.ExecuteSynchronously); return task; } private struct Void { } //因为没有非泛型的TaskCompletionSource类 public static async Task WithCancellation(this Task originalTask, CancellationToken token) { //创建在CancellationToken被取消时完成的一个Task var cancelTask = new TaskCompletionSource<Void>(); //一旦CancellationToken被取消就完成Task using (token.Register(t => ((TaskCompletionSource<Void>)t).TrySetResult(new Void()), cancelTask)) { //创建在原始Task或CancellationToken Task完成时都完成的一个Task Task any = await Task.WhenAny(originalTask, cancelTask.Task); if (any == cancelTask.Task) token.ThrowIfCancellationRequested(); } //等待原始任务(以同步方式):若任务失败,等待它将抛出第一个内部异常 而不是抛出AggregateException await originalTask; } }
class Program { static void Main() { Go(); } public static void Go() { ShowExceptions(); for (int i = 0; i < 3; i++) { try { switch (i) { case 0: throw new InvalidOperationException(); case 1: throw new ObjectDisposedException(""); case 2: throw new ArgumentOutOfRangeException(); } } catch { } } } private static async void ShowExceptions() { var eventAwaiter = new EventAwaiter<FirstChanceExceptionEventArgs>(); AppDomain.CurrentDomain.FirstChanceException += eventAwaiter.EventRaised; while (true) Console.WriteLine("AppDomain exception:{0}", (await eventAwaiter).Exception.GetType()); } } public sealed class EventAwaiter<TEventArgs> : INotifyCompletion { private ConcurrentQueue<TEventArgs> m_events = new ConcurrentQueue<TEventArgs>(); private Action m_continuation; //状态机先调用这个来获得awaiter 自己返回自己 public EventAwaiter<TEventArgs> GetAwaiter() { return this; } //告诉状态机是否发生了任何事件 public bool IsCompleted { get { return m_events.Count > 0; } } //状态机告诉我们以后要调用什么方法 把它保存起来 public void OnCompleted(Action continuation) { Volatile.Write(ref m_continuation, continuation); } //状态机查询结果 这是await操作符的结果 public TEventArgs GetResult() { TEventArgs e; m_events.TryDequeue(out e); return e; } //如果都引发了事件,多个线程可能同时调用 public void EventRaised(object sender, TEventArgs eventArgs) { m_events.Enqueue(eventArgs); //如果有一个等待进行的延续任务,该线程会运行它 Action continuation = Interlocked.Exchange(ref m_continuation, null); if (continuation != null) continuation(); //恢复状态机 } }