以释放所有资源,停止所有重要操作并正常终止。
虽然请求取消操作非常重要,但是我们更希望能够通过 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 和辅助代码就不必为细节而担心。
体系结构
我们可以创建使 UI 和辅助代码无需进行线程交互操作的体系结构。实际上我