外部引用 (DLL) 中的后台工作人员锁定主线程
我几乎每天都使用后台工作者并且效果很好。今天,我遇到了一个实例,我需要将后台工作人员放入一个单独的项目中,然后再运行我正在运行的项目,因为我需要在解决方案中的两个不同项目中使用此类。当我在 winforms 表单上测试编码时,它工作得很好,在后台线程上处理我的编码。当我尝试从外部项目引用此类时,我的所有编码似乎都运行得很好,但它似乎没有在后台线程上执行任何应有的操作,导致我的主窗口锁定。
有没有办法解决这个问题/外部类中异步调用的最佳实践是什么。
请注意,我基本上创建了一个名为 start 的类,并且当数据准备好时会触发一个事件,因此这不像我的外部项目正在等待该方法完成。
提前致谢
我的 senerio 解决方案示例
ABC 有两个项目。项目 A 和项目 B。项目 A 是我的 WPF 应用程序,B 是我执行工作的 DLL。内部项目 AI 有
Dim SmartCardData as new Solution.B()
SmartCardData.Start()
Project B has a sub
Public Sub Start()
worker.workerConnect.RunWorkerAsync()
End Sub
Private Sub workerConnect_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles workerConnect.DoWork
'loop 10 seconds connecting to my device
e.Result = true
End Sub
Private Sub workerConnect_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles workerConnect.RunWorkerCompleted
RaiseEvent Scanner_Connected()
End Sub
(抱歉,我无法让它以代码形式显示我的编码,而不是纯文本)
I use background worker almost daily and works great. Today I came to an instance though where I needed to put my background worker in a separate project then the one I was running because I needed to use this class in two different projects in my solution. When I tested the coding on a winforms form, it works perfectly, handling my coding on the background thread. When I try to reference this class from an external project, all of my coding seems to run just fine, but it does not appear to be doing anything on a background thread as it should be, causing my main window to lockup.
Is there any way around this / what is the best practice for ASYNC calls in an external class.
Note I basically created a class that u call start, and an event fires when data is ready, so it's not like my external project is waiting for the method to complete.
Thanks in advance
Example of my senerio
Solution ABC has two projects. Project A and Project B. Project A is my WPF application and B is my DLL doing the work. Inside project A I have
Dim SmartCardData as new Solution.B()
SmartCardData.Start()
Project B has a sub
Public Sub Start()
worker.workerConnect.RunWorkerAsync()
End Sub
Private Sub workerConnect_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles workerConnect.DoWork
'loop 10 seconds connecting to my device
e.Result = true
End Sub
Private Sub workerConnect_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles workerConnect.RunWorkerCompleted
RaiseEvent Scanner_Connected()
End Sub
(Sorry I can't get it to show my coding as code, not plain text)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
首先使用调试器。在 DoWork 事件处理程序上设置断点。当它中断时,使用“调试”+“Windows”+“线程”并验证它是否在工作线程上运行,并且您是否看到列出的主线程。双击主线程并查看调用堆栈,确保它处于空闲状态并且没有执行诸如等待 BGW 完成之类的操作。这肯定会陷入僵局。
下一种故障模式是难以诊断的。当您过于频繁地调用 ReportProgress 时,即使有后台工作线程,您也可以冻结 UI 线程。 UI 线程充斥着调用请求,无法再抽出时间执行其正常职责。就像绘画和响应输入一样。一切仍然正常工作,工作线程和 UI 线程实际上正在运行,只是你看不到而已。
这种情况很容易发生,每秒报告进度超过一千次就是危险区域。这取决于 UI 线程需要在 ProgressChanged 事件处理程序中完成多少工作。诊断这是否是您的问题的最佳方法是在 ReportProgress() 调用之后添加 System.Threading.Thread.Sleep(45) 。这通常会减慢工作线程的速度,让 UI 线程有机会赶上。
您可以通过以对人眼有用的速度报告进度来解决这个问题。每秒更新 25 次,除了模糊之外什么也看不到。将 bgw 结果收集到像 List<> 这样的集合对象中因此您可以通过一次调用(例如 AddRange())来更新 UI。如果 BGW 生成结果的速度远远快于 UI 消耗的速度,这可能仍然不够好,您将不得不跳过结果或人为地减慢工作人员的速度。
Use the debugger first. Set a breakpoint on the DoWork event handler. When it breaks, use Debug + Windows + Threads and verify that it runs on a worker thread and that you see the Main Thread listed. Double-click the main thread and look at the call stack, ensure it is idle and is not doing something like waiting for the BGW to complete. That's a guaranteed deadlock.
The next failure mode is one that's hard to diagnose. You can freeze the UI thread, even with a background worker, when you call ReportProgress too often. The UI thread is flooded with invoke requests and doesn't get around to doing its normal duties anymore. Like painting and responding to input. Everything still works like it should, the worker and the UI thread are actually running, you just can't see it.
This happens easily, reporting progress more than about a thousand times per second is the danger zone. It depends on how much work the UI thread needs to do in the ProgressChanged event handler. The best way to diagnose if that's your problem is to add System.Threading.Thread.Sleep(45) after the ReportProgress() call. This usually slows down the worker enough to give the UI thread a chance to catch up.
You solve it by reporting progress at a rate that's useful to human eyes. Which at 25 updates per second doesn't see anything but a blur anymore. Collect bgw results in a collection object like List<> so you can update the UI with a single call, something like AddRange(). This might still not be good enough if the BGW just generates results far faster than the UI can ever consume, you'll have to skip results or slow down the worker artificially.
后台工作人员在主线程中处理已完成的代码,从而阻止 UI 响应。如果您不希望 UI 在后台工作程序完成时更新,请不要使用后台工作程序。
The background worker handles it completed code in the main thread stoppping the UI from responding. Don't use the background worker if you wan't the UI to update while the backgroundworker is finishing.
如果您的外部应用程序是基于控制台的,请使用 ThreadPool 来运行异步工作。 BackgroundWorker 委托需要一个消息泵才能在主线程上执行。
If your external app is consoled based, use the ThreadPool instead to run your async work. The BackgroundWorker delegate needs a message pump in order to execute on the main thread.