扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
在本页阅读全文(共2页)
在应用程序中使用多线程的原因有多种,但最常见的原因是我们一方面需要执行一个长时间运行的任务,另一方面又希望某些或所有用户界面对用户来说始终处于响应状态。
至少我们应该使 Cancel(取消)按钮始终保持响应状态,使用户能够通过它告诉系统,他们希望终止长时间运行的任务。
在 Visual Basic 6 中,我们尝试使用 DoEvents、计时器控件和许多其他方法进行该操作。Visual Basic .NET 中的操作则简单得多,因为我们可以使用多线程。而且,只要我们小心谨慎,就可以完成此操作且不会使代码或调试复杂化。
要在多线程环境中成功实现 Cancel(取消)按钮,关键是要记住 Cancel(按钮)的作用只是“请求”取消任务。由后台任务决定何时停止。
如果我们实现一个能够直接停止后台进程的 Cancel(取消)按钮,则可能会在执行某些敏感性操作的过程中将其停止,或者在后台进程关闭重要资源(例如,文件处理程序或数据库连接)之前将其停止。而这有可能导致严重后果,引起死机、应用程序行为不稳定或应用程序完全崩溃。
因此,Cancel(取消)按钮的作用应该只是请求停止后台任务。后台任务可以检查某一时间点上是否存在取消操作的请求。如果检测到取消操作的请求,后台线程则可以释放所有资源,停止所有重要操作并正常终止。
虽然请求取消操作非常重要,但是我们更希望能够通过 UI 为用户显示后台进程的状态信息。状态信息可以是文本格式的消息,也可以是完成任务的百分比,或者同时显示两种消息。
要在 Visual Basic .NET 中实现 Cancel(取消)按钮或状态显示,我们所面对的最复杂的问题在于 Windows 窗体库不是对于线程并不安全。这意味着只有创建窗体的线程可以与该窗体或其控件进行交互。其他线程均不能安全地与该窗体或其控件进行交互。
但是,我们却无法避免编写多线程与给定窗体进行交互的代码。因此,运行时可能会产生不可预知的后果,甚至可能会导致应用程序崩溃。
这要求我们在编码时必须小心谨慎,还要确保只有我们的 UI 线程与 UI 进行交互。为此,我们可以建立一个简单的架构,管理后台辅助线程和 UI 线程之间的交互。如果能够实现,则可以使 UI 代码和长时间运行的任务的代码都相对清楚地了解到我们正在使用多线程。
如果要创建一个后台进程并使其可以使用它自己的数据在它自己的线程上运行,最简单的方法是创建专门用于该后台进程的对象。虽然不一定能实现,但它是一个积极的目标,因为它能够大大简化多线程应用程序的创建过程。
如果后台线程在其自身的对象中运行,则后台线程可以使用该对象的实例变量(在类中声明的变量),而无须担心这些变量会被其他线程使用。例如,请考虑下面的类:
Public Class Worker Private mInner As Integer Private mOuter As Integer Public Sub New(ByVal InnerSize As Integer, ByVal OuterSize As Integer) mInner = InnerSize mOuter = OuterSize End Sub Public Sub Work() Dim innerIndex As Integer Dim outerIndex As Integer Dim value As Double For outerIndex = 0 To mOuter For innerIndex = 0 To mInner ' do some cool calculation here value = Math.Sqrt(CDbl(innerIndex - outerIndex)) Next Next End Sub End Class
这个类适合在后台线程中运行,并且可以使用以下代码启动:
Dim myWorker As New Worker(10000000, 10) Dim backThread As New Thread(AddressOf myWorker.Work) backThread.Start()
Worker 类中的实例变量可以存放其数据。后台线程可以安全地使用这些变量(mInner 和 mOuter),还可以确保其他线程不会同时访问这些变量。
我们可以用其中包含的 constructor 方法使用任何起始数据初始化该对象。实际启动后台线程之前,我们的主应用程序代码会创建此对象的实例,并使用后台线程将要操作的数据对其进行初始化。
后台线程将获取对象的 Work 方法的地址,然后开始启动。此线程将立即在对象内部运行代码,并使用该对象的专用数据。
由于对象是自包含的,因此我们可以创建多个对象,每个对象在其自身的线程上运行并且对象之间相对独立。
但是,此实现方案并不理想。UI 无法获得后台进程的状态。我们也未实现任何机制,使 UI 能够请求终止后台进程。
要解决以上两个问题,后台线程与 UI 线程之间需要以某种方式进行交互。这种交互方式非常复杂,因此最好能够以某种方式将交互放到一个类中,这样 UI 和辅助代码就不必为细节而担心。
如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。
现场直击|2021世界人工智能大会
直击5G创新地带,就在2021MWC上海
5G已至 转型当时——服务提供商如何把握转型的绝佳时机
寻找自己的Flag
华为开发者大会2020(Cloud)- 科技行者