关于使用NAudio麦克风扬声器组件造成WPF应用程序卡死问题跟踪及异步队列的实现
由于WPF应用程序出现卡死的情况,特记录一下问题的跟踪情况
1、多次进行NAudio事件注册,没有启用注销再注册的方式,造成应用程序CPU过高
private AudioNotificationClient audioNotification = new AudioNotificationClient();
audioNotification.DeviceStateChanged += AudioNotification_DeviceStateChanged;
private MMDeviceEnumerator _mmDeviceEnumerator = new MMDeviceEnumerator();
_mmDeviceEnumerator.RegisterEndpointNotificationCallback(audioNotification);
缺少注销
_mmDeviceEnumerator.UnregisterEndpointNotificationCallback(audioNotification);
2、事件注册同时麦克风设备状态发生改变DeviceStateChanged,造成线程死锁
可以使用异步队列,把事件的注册,注销与DeviceStateChanged执行逻辑都放进异步队列,保证不会出现同时执行的情况。
异步队列的实现:
/// <summary> /// 异步任务队列 /// </summary> public class AsyncTaskQueue : IDisposable { private bool _isDisposed; private readonly ConcurrentQueue<AwaitableTask> _queue = new ConcurrentQueue<AwaitableTask>(); private Thread _thread; private AutoResetEvent _autoResetEvent; /// <summary> /// 异步任务队列 /// </summary> public AsyncTaskQueue() { _autoResetEvent = new AutoResetEvent(false); _thread = new Thread(InternalRuning) {IsBackground = true}; _thread.Start(); } private bool TryGetNextTask(out AwaitableTask task) { task = null; while (_queue.Count > 0) { if (_queue.TryDequeue(out task) && (!AutoCancelPreviousTask || _queue.Count == 0)) return true; task.Cancel(); } return false; } private AwaitableTask PenddingTask(AwaitableTask task) { lock (_queue) { Debug.Assert(task != null); _queue.Enqueue(task); _autoResetEvent.Set(); } return task; } private void InternalRuning() { while (!_isDisposed) { if (_queue.Count == 0) { _autoResetEvent.WaitOne(); } while (TryGetNextTask(out var task)) { if (task.IsCancel) continue; if (UseSingleThread) { task.RunSynchronously(); } else { task.Start(); } } } } /// <summary> /// 是否使用单线程完成任务. /// </summary> public bool UseSingleThread { get; set; } = true; /// <summary> /// 自动取消以前的任务。 /// </summary> public bool AutoCancelPreviousTask { get; set; } = false; /// <summary> /// 执行任务 /// </summary> /// <param name="action"></param> /// <returns></returns> public AwaitableTask Run(Action action) => PenddingTask(new AwaitableTask(new Task(action, new CancellationToken(false)))); /// <summary> /// 执行任务 /// </summary> /// <typeparam name="TResult"></typeparam> /// <param name="function"></param> /// <returns></returns> public AwaitableTask<TResult> Run<TResult>(Func<TResult> function) => (AwaitableTask<TResult>) PenddingTask(new AwaitableTask<TResult>(new Task<TResult>(function))); /// <inheritdoc /> public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } /// <summary> /// 析构任务队列 /// </summary> ~AsyncTaskQueue() => Dispose(false); private void Dispose(bool disposing) { if (_isDisposed) return; if (disposing) { _autoResetEvent.Dispose(); } _thread = null; _autoResetEvent = null; _isDisposed = true; } /// <summary> /// 可等待的任务 /// </summary> public class AwaitableTask { private readonly Task _task; /// <summary> /// 初始化可等待的任务。 /// </summary> /// <param name="task"></param> public AwaitableTask(Task task) => _task = task; /// <summary> /// 任务的Id /// </summary> public int TaskId => _task.Id; /// <summary> /// 任务是否取消 /// </summary> public bool IsCancel { get; private set; } /// <summary> /// 开始任务 /// </summary> public void Start() => _task.Start(); /// <summary> /// 同步执行开始任务 /// </summary> public void RunSynchronously() => _task.RunSynchronously(); /// <summary> /// 取消任务 /// </summary> public void Cancel() => IsCancel = true; /// <summary> /// 获取任务等待器 /// </summary> /// <returns></returns> public TaskAwaiter GetAwaiter() => new TaskAwaiter(this); /// <summary>Provides an object that waits for the completion of an asynchronous task. </summary> [HostProtection(SecurityAction.LinkDemand, ExternalThreading = true, Synchronization = true)] public struct TaskAwaiter : INotifyCompletion { private readonly AwaitableTask _task; /// <summary> /// 任务等待器 /// </summary> /// <param name="awaitableTask"></param> public TaskAwaiter(AwaitableTask awaitableTask) => _task = awaitableTask; /// <summary> /// 任务是否完成. /// </summary> public bool IsCompleted => _task._task.IsCompleted; /// <inheritdoc /> public void OnCompleted(Action continuation) { var This = this; _task._task.ContinueWith(t => { if (!This._task.IsCancel) continuation?.Invoke(); }); } /// <summary> /// 获取任务结果 /// </summary> public void GetResult() => _task._task.Wait(); } } /// <summary> /// 可等待的任务 /// </summary> /// <typeparam name="TResult"></typeparam> public class AwaitableTask<TResult> : AwaitableTask { /// <summary> /// 初始化可等待的任务 /// </summary> /// <param name="task">需要执行的任务</param> public AwaitableTask(Task<TResult> task) : base(task) => _task = task; private readonly Task<TResult> _task; /// <summary> /// 获取任务等待器 /// </summary> /// <returns></returns> public new TaskAwaiter GetAwaiter() => new TaskAwaiter(this); /// <summary> /// 任务等待器 /// </summary> [HostProtection(SecurityAction.LinkDemand, ExternalThreading = true, Synchronization = true)] public new struct TaskAwaiter : INotifyCompletion { private readonly AwaitableTask<TResult> _task; /// <summary> /// 初始化任务等待器 /// </summary> /// <param name="awaitableTask"></param> public TaskAwaiter(AwaitableTask<TResult> awaitableTask) => _task = awaitableTask; /// <summary> /// 任务是否已完成。 /// </summary> public bool IsCompleted => _task._task.IsCompleted; /// <inheritdoc /> public void OnCompleted(Action continuation) { var This = this; _task._task.ContinueWith(t => { if (!This._task.IsCancel) continuation?.Invoke(); }); } /// <summary> /// 获取任务结果。 /// </summary> /// <returns></returns> public TResult GetResult() => _task._task.Result; } }