线程传递数据和窗口closures
我创build了一个简单的WPF项目,在button单击我创build一个单独的线程与新窗口,并将数据传递给它。 在应用程序退出时,我试图closures该线程/窗口。 但是,偶尔会遇到以下exception,这会导致应用程序不稳定。
所以我的问题是如何妥善处理这种情况。 谢谢
在线:
Dispatcher.Invoke(new Action(() =>
我有
A first chance exception of type 'System.Threading.ThreadAbortException' occurred in mscorlib.dll Additional information: Thread was being aborted.
我的视图有以下代码:
构造函数
public MyView(ConcurrentQueue<MyItem> actionReports, ManualResetEvent actionCompletedEvent, string actionName) { _actionReports = actionReports; _actionCompletedEvent = actionCompletedEvent; _actionName = actionName; InitializeComponent(); DataContext = this; this.Loaded += MyView_Loaded; } void MyView_Loaded(object sender, RoutedEventArgs e) { var worker = new BackgroundWorker(); worker.DoWork += (o, ea) => { while (true) { if (_actionCompletedEvent.WaitOne(0)) { // Issue Dispatcher.Invoke(new Action(() => { Close(); })); Thread.Sleep(100); } while (!_actionReports.IsEmpty) { // Do some stuff } } }; worker.RunWorkerAsync(); }
窗口的初始化
public WindowLauncher(ManualResetEvent actionCompletedEvent, ManualResetEvent reportWindowClosedEvent, string actionName) { _actionCompletedEvent = actionCompletedEvent; _reportWindowClosedEvent = reportWindowClosedEvent; _actionName = actionName; Thread thread = new Thread(new ThreadStart(() => { _reportWindow = new MyView(_messageQueue, _actionCompletedEvent, actionName); _reportWindow.Show(); // InvokeShutdown to terminate the thread properly _reportWindow.Closed += (sender, args) => { _reportWindow.Dispatcher.InvokeShutdown(); }; _resetEvent.Set(); Dispatcher.Run(); })); thread.Name = "MyWindowThread"; thread.SetApartmentState(ApartmentState.STA); thread.IsBackground = true; thread.Start(); }
我通常至less会尝试取消Window.OnClosing
事件中的BackgroundWorker
asynchronous操作,并捕获挂起的取消。 你仍然需要注意ThreadAbortExceptions但是只有当你的asynchronous进程是长时间运行的。
private BackgroundWorker _worker; private void MyView_Loaded(object sender, RoutedEventArgs e) { _worker = new BackgroundWorker(); _worker.WorkerSupportsCancellation = true; _worker.DoWork += (o, ea) => { while (true) { if (_actionCompletedEvent.WaitOne(0)) { if (_worker.CancellationPending) { ea.Cancel = true; return; } // Issue Dispatcher.Invoke(new Action(() => { Close(); })); Thread.Sleep(100); } while (!_actionReports.IsEmpty) { // Do some stuff } } }; } protected override void OnClosing(CancelEventArgs e) { _worker.CancelAsync(); }
后台线程会在您的应用退出时由运行时自动中止。 通常他们不会抛出ThreadAbortExceptions
(请参阅前台和后台线程 )
调用调度程序会导致在调度线程上运行一个方法,但由于您使用了Invoke()
而不是BeginInvoke()
,调度程序需要通知后台线程该方法已完成。 我怀疑这是例外情况,但这只是我自己的猜想。
尝试捕捉像这样的exception:
try { Dispatcher.Invoke(new Action(() => { Close(); })); } catch (ThreadAbortException) { Thread.ResetAbort(); }
虽然这可能无助于如果在调度线程上引发exception。 如果这不起作用,请尝试BeginInvoke()
。
顺便说一句,如果你在调用lambda的开始处延迟某些延迟,并且closures应用程序,那么你可以更容易地重现这个bug。 这意味着后台线程将在lambda完成时被中止。