当我们的程序运行时,调用了一段异步的逻辑A,这段异步的逻辑无法转化为同步(如动画、下载进度等)
而,我们又需要等待异步逻辑A处理完成,然后再执行其它逻辑B。
AutoResetEvent 同步转异步
AutoResetEvent autoResetEvent = new AutoResetEvent(false)
AutoResetEvent 可以在线程间发送信号互相通信,通过调用 AWaitOne 来等待信号,调用Set发送信息来启动已等待的线程。
很简单:一个await ,另一个set来唤醒。
- AutoResetEvent autoResetEvent = new AutoResetEvent(false)--参数bool:若要将初始状态设置为终止,则为 true;若要将初始状态设置为非终止,则为 false
- await Task.Run(() => { autoResetEvent.WaitOne(); });
- autoResetEvent.Set();
比如:
private async Task SetDelegateProgress() { var delegateProgress = new UIDelegateProgress(); delegateProgress.ProgressCompleted += () => { autoResetEvent.Set(); }; DelegateProgress = delegateProgress; await Task.Run(() => { autoResetEvent.WaitOne(); }); }
如上案例,当delegateProgress执行完后,通过AutoResetEvent 的方法Set来发送信息来唤醒子线程。
再如动画的同步等待处理:
1 /// <summary> 2 /// 执行动画 3 /// </summary> 4 /// <param name="storyboard"></param> 5 /// <returns></returns> 6 public static async Task ExecuteStoryboradAsync([NotNull] Storyboard storyboard) 7 { 8 if (storyboard == null) throw new ArgumentNullException(nameof(storyboard)); 9 10 AutoResetEvent autoResetEvent = new AutoResetEvent(false); 11 12 storyboard.Completed += OnStoryboardCompleted; 13 storyboard.Begin(); 14 15 void OnStoryboardCompleted(object sender, EventArgs e) 16 { 17 storyboard.Completed -= OnStoryboardCompleted; 18 autoResetEvent.Set(); 19 } 20 21 await Task.Run(() => { autoResetEvent.WaitOne(); }); 22 }
值得注意的是,WaitOne只能在子线程,如果放在主线程的话,会将整个线程终止(例如界面或者其它后台逻辑)
AutoResetEvent 可以在多个线程使用WaitOne来暂停线程,而暂停的线程则需要多次set来开启暂停的线程。
给你AutoResetEvent 类似的,还有一个ManualResetEvent。ManualResetEvent 是多个暂停线程,可以通过一次set直接开启全部暂停的线程。
ManualResetEvent与AutoResetEvent 不同的还有Reset方法,Reset与Set相反,为主动暂停线程。
详细ManualResetEvent & AutoResetEvent可参考:https://www.cnblogs.com/maitian-lf/p/3672390.html
缺陷
使用AutoResetEvent的确可以由同步转成异步方法,但是以上方案是创建了一个新的任务,如果是大量的处理会有性能问题~
关键字:动画同步,AutoResetEvent