线程和对象
创建在自己的线程上使用自己的数据运行的后台处理的最简单的方法是为该后台处理建立一个对象。虽然这不一定可行,但却是一个好的目标,因为它从根本上简化了多线程应用程序。
如果后台线程在自己的对象中运行,它可以使用该对象的实例变量(在类中声明的变量),而不需担心它们被其它的线程使用了。例如,考虑下面的类:
| 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方法的地址给后台线程后,它才被载入。该线程将使用对象中给定的数据运行的代码。
由于该对象是自我包含(self-contained)的,我们能建立多个对象,每一个在它们自己的线程上运行并且彼此隔离。
这种实现并不理想。UI没有办法知道后台处理的状态。我们也没有执行任何机制使得UI可以查询到后台处理已经终止了。
所有这些情况都需要后台线程以某种方式与UI线程交互。这种交互很复杂,因此如果我们能用某种方式抽象化这种交互,将它们放入一个类中将会很有利,这样UI和工作代码都不需要担心细节。
体系结构
我们可以建立一个体系结构来保护UI和工作代码,防止它们进行线程间交互。事实上,我们可以实现一个构架来执行那些复杂代码,我们能使用该构架来管理或控制后台线程与UI的交互。
首先让我们讨论该体系结构,然后再设计和实现该代码。
典型的情况下,一个应用程序以一个线程开始,该线程打开用户界面。为了直观我们称该线程为UI线程。在很多应用程序中这是唯一的线程,因此它控制UI并做所有的处理。
在本例中,我们将建立一个工作线程从事后台处理,让UI线程聚焦于用户界面,这样工作线程在忙于工作时,UI线程仍然可以响应用户。
在UI线程与工作线程之间我们插入一层代码作为UI和工作代码间的接口。该代码本质上是控制器(Controller),管理和控制工作线程与UI线程间的交互。
图1:UI线程,控制器和工作线程
控制器将包含所有这些代码:安全地开始工作线程,将工作线程的任何状态信息传递给UI线程,将任何“取消”请求从UI线程传递给工作线程。UI代码与工作代码并不直接交互;它们通过控制器代码交互。
上一页 [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] 下一页