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(); //恢复状态机
}
}