多线程应用程序(C# 和 Visual Basic)

使用 Visual Basic 和 C# 可以编写同时执行多项任务的应用程序。有潜力支持其他一些任务的任务能够在不同的线程上执行,这种进程被称为“多线程处理”或“自由线程处理”。

使用多线程处理的应用程序对用户输入的响应能力更强,因为大量占用处理器的任务在不同的线程上执行时,用户接口是活动的。多线程处理在创建可缩放应用程序时也很有用,因为工作量增加时可以添加线程。

说明说明

Visual Studio 2010 和 .NET Framework 4 提供了新的运行时、新的类库类型以及新的诊断工具,从而增强了对并行编程的支持。有关更多信息,请参见.NET Framework 中的并行编程

使用 BackgroundWorker 组件

创建多线程处理应用程序的最可靠方法是使用 BackgroundWorker 组件。此类管理一个专用于处理您指定的方法的单独线程。有关示例,请参见演练:利用 BackgroundWorker 组件进行多线程处理(C# 和 Visual Basic)

若要在后台开始一项操作,请创建 BackgroundWorker,并侦听报告操作进度和在操作完成时发出信号的事件。可以通过编程方式创建 BackgroundWorker 对象,也可以将它从**“工具箱”“组件”选项卡中拖到窗体上。如果在“窗体设计器”中创建 BackgroundWorker,则它会出现在“组件栏”中,而且它的属性会显示在“属性”**窗口中。

为后台操作做好准备

若要为后台操作做好准备,请添加 DoWork 事件的事件处理程序。在此事件处理程序中调用耗时的操作。

若要开始此操作,请调用 RunWorkerAsync。若要收到进度更新的通知,请处理 ProgressChanged 事件。若要在操作完成时收到通知,请处理 RunWorkerCompleted 事件。

处理 ProgressChangedRunWorkerCompleted 事件的方法可以访问应用程序的用户界面,原因是这两个事件是在调用了 RunWorkerAsync 方法的线程上引发的。但是,DoWork 事件处理程序无法使用任何用户界面对象,因为它在后台线程上运行。

创建和使用线程

如果需要对应用程序的线程的行为进行更多的控制,则可以自己管理线程。但请注意,编写正确的多线程应用程序可能很困难:应用程序可能会因为争用条件而停止响应或遇到瞬态错误。有关更多信息,请参见线程安全组件

通过声明类型为 Thread 的变量,并调用为要对新线程执行的过程或方法提供名称的构造函数,从而创建一个新线程。以下代码提供了一个示例。

Dim newThread As New System.Threading.Thread(AddressOf AMethod)
System.Threading.Thread newThread =
    new System.Threading.Thread(AMethod);

ck8bc5c6.collapse_all(zh-cn,VS.110).gif启动和停止线程

若要开始执行新线程,可使用 Start 方法,如以下代码所示。

newThread.Start()
newThread.Start();

若要停止执行线程,可使用 Abort 方法,如以下代码所示。

newThread.Abort()
newThread.Abort();

除启动和停止线程之外,还可以通过调用 SleepSuspend 方法暂停线程、使用 Resume 方法继续挂起的线程,以及使用 Abort 方法销毁线程

ck8bc5c6.collapse_all(zh-cn,VS.110).gif线程方法

下表显示了一些可用于控制单个线程的方法。

方法

操作

Start

使线程开始运行。

Sleep

使线程暂停指定的一段时间。

Suspend

在线程到达安全点时,使其暂停。

Abort

在线程到达安全点时,使其停止。

Resume

重新启动挂起的线程

Join

使当前线程一直等到另一线程完成。在与超时值一起使用时,如果该线程在分配的时间内完成,此方法将返回 True。

ck8bc5c6.collapse_all(zh-cn,VS.110).gif安全点

这些方法大多数都一目了然,但安全点对您可能是个新概念。安全点是指代码中公共语言运行时可以安全地执行自动“垃圾回收”的位置。垃圾回收是指释放不再使用的变量并回收内存的过程。调用线程的 AbortSuspend 方法时,公共语言运行时将对代码进行分析,确定让线程停止运行的适当位置。

ck8bc5c6.collapse_all(zh-cn,VS.110).gif线程属性

线程也包含许多有用的属性,如下表所示:

属性

IsAlive

如果线程处于活动状态,则包含值 True。

IsBackground

获取或设置一个布尔值,该值表示一个线程是否是或是否应当是后台线程。后台线程与前台线程类似,但后台线程不阻止进程停止。一旦某个进程的所有前台线程都停止,公共语言运行时就会对仍处于活动状态的后台线程调用 Abort 方法,从而结束该进程。

Name

获取或设置线程的名称。通常用于在调试时发现各个线程。

Priority

获取或设置操作系统用于确定线程调度优先顺序的值。

ApartmentState

获取或设置用于特定线程的线程模型。线程模型在线程调用非托管代码时很重要。

ThreadState

包含描述线程状态的值。

线程优先级

每个线程都有一个优先级属性,用于确定其执行所占用的处理器时间片大小。操作系统为高优先级线程分配较长的时间段,并为低优先级线程分配较短的时间段。新创建的线程具有值 Normal,但您可以将 Priority 属性更改为 ThreadPriority 枚举中的任何值。

有关各种线程优先级的详细说明,请参见 ThreadPriority

前台和后台线程

前台线程的运行时间不限定,而后台线程则在最后一个前台线程停止时立即停止。可以使用 IsBackground 属性确定或更改线程的后台状态。

多线程处理窗体和控件

虽然多线程处理最适于运行过程和类方法,它也可以用于窗体和控件。使用时,请注意以下几点:

  • 只要有可能,便仅在用来创建它的线程上执行控件的各种方法。如果必须从另一个线程中调用控件的方法,则必须使用 Invoke 来调用该方法。

  • 不要使用 SyncLock (Visual Basic) 或 lock (C#) 语句来锁定操作控件或窗体的线程。由于控件和窗体的方法有时回调到调用过程,因此可能会因无意中创建了死锁而终止运行(死锁是指两个线程都等待对方释放锁定,从而导致应用程序暂停的情况)。

请参见

参考

线程同步(C# 和 Visual Basic)

Invoke

InvokeRequired

Thread

概念

多线程过程的参数和返回值(C# 和 Visual Basic)

其他资源

组件中的多线程处理

HOW TO: Create a Thread by Using Visual C#(如何:使用 Visual C# 创建线程)